статический assert зависит от параметра шаблона не-типа (различное поведение на 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 [temp.res] / 8

это применяется сразу после того, как основной шаблон определен (тот, с static_assert в нем). Так что позже специализация (для 42) нельзя рассматривать, так как он еще не существует.

следующий вопрос: если static_assert( sizeof(answer) != sizeof(answer), зависит on answer. Семантически это не так, синтаксически это так, и стандартно:

внутри шаблона, некоторые конструкции имеют семантику, которая может отличаться от одного экземпляра к другому. Такая конструкция зависит параметры шаблона.

N4296 [температура.dep] / 1

конструкция sizeof(answer) != sizeof(answer) ничем не отличается от одного экземпляра к другому. Так что такая конструкция не зависит параметры шаблона. Что означает все static_assert не зависит от параметра шаблона.

таким образом, ваша программа плохо сформирована, диагностика не требуется. Выдача произвольной диагностики (например,static_assert failing) является допустимым поведением компилятора. Отсутствует проблема-допустимое поведение компилятора. Этот поведение программы, скомпилированной из плохо сформированной, никакой диагностической программы не определяется стандартом: это неопределенное поведение. Носовые демоны разрешены.

необычные попытки (например,sizeof(int[answer])!=sizeof(int[answer]) может, пожалуйста, тег черт компилятор, но не делает вашу программу более хорошо сформированной.

вы можете сделать случай, когда компилятор вряд ли сможет поймать вас на этом, но плохо сформированная-ness остается независимо от способности для компилятора чтобы поймать тебя с ним. Как правило, C++ хочет оставить себе (и своим компиляторам) свободу поиска недопустимого кода шаблона "раньше, чем создание экземпляра"; это означает, что код шаблона должен производить, возможно, юридический код.

возможно, вы хотите что-то вроде =delete с прикрепленным сообщением.


оба компилятора верны. От [temp.res] / 8:

Если для шаблона не может быть создана допустимая специализация, и этот шаблон не создается, шаблон неправильно сформирован, нет диагностики требуемый.

не существует допустимой специализации, которая может быть создана из основного шаблона Hitchhiker, поэтому он плохо сформирован, не требуется диагностика. клэнг все равно решает провести диагностику.

Если вы только хотите разрешить 42, тогда просто не определяйте общий шаблон:

template <int > struct Hitchhiker;
template <> struct Hitchhiker<42> {};