статическое утверждение, зависящее от параметра шаблона не-типа (различное поведение на 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 23

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> {};