Специализация шаблона с преобразованием типов
Я нашел этот кусок поддельного кода (придуманный пример ниже):
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 ответа:
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
без знака) и, таким образом, не является простой идентификатор.