Относительно ошибки переопределения Clang см. этот вопрос .
Первоначально идентификаторы шаблонов шаблонов псевдонимов, таких как std::void_t
, просто заменялись бы их типом псевдонимов без проверки аргументов для подстановки. отказ. Это было изменено с CWG выпуск 1558 . Это только изменило стандарт, требуя выполнения замены подстановки в аргументах шаблона, но не проясняет, следует ли считать два шаблона, которые будут эквивалентными после замены псевдонима, эквивалентными. Кланг считает их эквивалентными, а G CC - нет. Это открытый CWG выпуск 1980 .
С -pedantic-errors
G CC сообщает о серьезной ошибке уже для
std::cout << absolute<5>() << std::endl;
в специализации
template<int p>
struct absolute<p, typename std::void_t<int[-p]>>
потому что предположительно размер массива не является константным выражением. Размер массива должен быть преобразованным константным выражением типа std::size_t
. Преобразованное константное выражение может использовать только не сужающие преобразования. Таким образом, верно, что -p
с p = 5
, преобразованным в std::size_t
, не является константным выражением, что делает тип int[-p]
некорректным, но я думаю, что это должно вызвать сбой замещения, а не серьезную ошибку. [temp.deduct / 8] стандарта C ++ 17 (черновик N4659) гласит:
Если замена приводит к недопустимому типу или выражению, вывод типа завершается неудачно. Недопустимый тип или выражение - это неправильно сформированный тип с необходимостью диагностики c, если он написан с использованием замещенных аргументов.
И это применимо здесь. Ненормативные примеры, приведенные в следующей цитате, даже включают отрицательные размеры массива в качестве примера ошибки замещения.
Особенно странно, что для absolute<-5>()
G CC не сообщает эквивалентная ошибка в специализации
template<int p>
struct absolute<p, typename std::void_t<int[p]>>
, где int[p]
будет иметь значение int[-5]
, которое также не имеет преобразованного размера константного выражения.
absolute<0>()
выбирает основной шаблон, потому что размеры массива должны быть больше нуля, что делает частичные специализации нежизнеспособными. Массивы нулевого размера - это расширение языка, которое можно отключить с помощью -pedantic-errors
в G CC и Clang.