Специализация шаблонов с преобразованием типов
Я нашел этот кусок фиктивного кода (надуманный пример ниже):
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
. Что происходит? Он по-прежнему считается специализацией по стандарту?
Ответы
Ответ 1
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
}
Смотрите live пример. И этот код должен сообщать о двусмысленной частичной специализации, но это не (для gcc). Clang отчет "неоднозначный" .
PS Я утверждаю, что эта часть не достаточно покрыта стандартом.
Обновление
clang в этой ситуации не будет работать с перечислениями, .
Ответ 2
Ограничения на частичную специализацию шаблона класса в аргументе шаблона несимметричного шаблона 14.5.5 [temp.class.spec] в пункте 8 перечисляют следующее ограничение:
Частично специализированное несимвольное выражение аргумента не должно включать параметр шаблона частичной специализации, за исключением случаев, когда выражение аргумента является простым идентификатором.
Выражение аргумента с использованием size_t
включает преобразование в int
(size_t
не указано) и, следовательно, не является простым идентификатором.