статическое утверждение, зависящее от параметра шаблона не-типа (различное поведение на gcc и clang)
template <int answer> struct Hitchhiker {
static_assert(sizeof(answer) != sizeof(answer), "Invalid answer");
};
template <> struct Hitchhiker<42> {};
При попытке отключить общий экземпляр шаблона с помощью static_assert
я обнаружил, что приведенный выше код в clang
генерирует ошибку assert, даже если шаблон не создан, а gcc
генерирует ошибку assert только при создании экземпляра Hitchhiker
с параметром, отличным от 42
.
Возясь я обнаружил, что это утверждение:
template <int answer> struct Hitchhiker {
static_assert(sizeof(int[answer]) != sizeof(int[answer]), "Invalid answer");
};
template <> struct Hitchhiker<42> {};
Ведет себя одинаково на обоих компиляторах: assert срабатывает только при создании экземпляра общего шаблона.
Что делает стандарт говорит, какой компилятор прав?
g++ 4.9.2
clang++ 3.50
2 ответа:
Цитаты, найденные @TartainLlama
Если гипотетический экземпляр шаблона, непосредственно следующий за его определением, был бы неправильно сформирован из-за конструкции, которая не зависит от параметра шаблона, программа плохо сформирована; никакая диагностика не требуется.
N4296 [темп.res]/8
Это применяется сразу после определения основного шаблона (того, в котором находится
static_assert
). Таким образом, более поздняя специализация (для42
) не может быть считается, как его пока не существует.Следующий вопрос: если
static_assert( sizeof(answer) != sizeof(answer),
зависит отanswer
. Семантически это не так, синтаксически это так, и стандартно:Внутри шаблона некоторые конструкции имеют семантику, которая может отличаться от одного экземпляра к другому. Такая конструкция зависит от параметров шаблона.N4296 [темп.dep]/1
Конструкция
Таким образом, ваша программа плохо сформирована, никакой диагностики не требуется. Выдача произвольной диагностики (например, ошибкаsizeof(answer) != sizeof(answer)
не отличается от одного экземпляра к другому. другой. Таким образом, такая конструкция не зависит от параметров шаблона. Это означает, что весьstatic_assert
не зависит от параметра шаблона.static_assert
) является допустимым поведением компилятора. Отсутствует проблема допустимого поведения компилятора. Поведение программы, скомпилированной из плохо сформированной, не требующей диагностики программы, не определяется стандартом: это неопределенное поведение. Носовые демоны разрешены.Причудливые попытки (например,
sizeof(int[answer])!=sizeof(int[answer])
могут понравиться текущему компиляторуgod, но не делают вашу программу более хорошо сформированной.Вы можете сделать случай, когда компилятор вряд ли сможет поймать вас на этом, но неправильность остается независимо от способности компилятора поймать вас с этим. Как правило, C++ хочет оставить себе (и своим компиляторам) свободу находить недопустимый шаблонный код " раньше, чем инстанциация"; это означает, что код шаблона должен производить, возможно, юридический код.
Возможно, вы хотите что-то вроде
=delete
с прикрепленным сообщением.
Оба компилятора верны. От [темп.res] / 8:
Если для шаблона не может быть сгенерирована допустимая специализация и этот шаблон не создан, то шаблон плохо сформирован, никакой диагностики нет. требуемый.
Не существует допустимой специализации, которая может быть сгенерирована из первичного шаблона
Hitchhiker
, поэтому она плохо сформирована и не требует диагностики. клэнг все равно решает провести диагностику.Если вы только хотите разрешить
42
, то просто не делайте этого определите общий шаблон:template <int > struct Hitchhiker; template <> struct Hitchhiker<42> {};