Специализация шаблона с преобразованием типов


Я нашел этот кусок поддельного кода (придуманный пример ниже):

template <int I, typename T>
struct foo
{
    static int bar()
    {
        return 1;
    }
};

template <std::size_t Index, typename T>
struct foo<Index, T*>
{
    static int bar()
    {
        return 2;
    }
};
Обратите внимание, что специализация использует разные типы (по ошибке). Удивительно, но он компилируется без каких-либо ошибок (или предупреждений) как с GCC 4.8.1, так и с Clang 3.4. Но что еще более странно для GCC строка foo<0, int*>::bar() приводит к 1, а Clang дает 2. Что происходит? Это все еще рассматривается как специализация по стандарту?
2 14

2 ответа:

Gcc ошибается, потому что вы просто не можете назвать это специализацией. Просто удалите определение основного шаблона:

template <int I, typename T>
struct foo;

template <std::size_t Index>
struct foo<Index, int*> {
  static int bar() {
    return 2;
  }
};

int main() {
  std::cout << foo<std::size_t(0), int*>::bar() << std::endl; // nope, not work
  std::cout << foo<0, int*>::bar() << std::endl; // nope, not work
}

Смотрите живойПример . Иэтот код должен сообщать о неоднозначной частичной специализации, но это не так (для gcc). Clang report "неоднозначно".

PS Я считаю, что эта часть недостаточно охвачена стандартом.

Обновить

Clang в этой ситуации не будет работать с перечислениями , пример .

Ограничения на частичную специализацию шаблона класса на аргументе шаблона не-типа 14.5.5 [temp.класс.в пункте 8 перечисляются следующие ограничения:

Частично специализированное выражение аргумента без типа не должно включать шаблонный параметр частичной специализации, за исключением случаев, когда выражение аргумента является простым идентификатором.

Выражение аргумента, использующее size_t, включает преобразование в int (size_t без знака) и, таким образом, не является простой идентификатор.