Подтвердить что ты не робот

Static_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 kicks только в том случае, когда создается общий шаблон.

Что говорит стандарт, какой компилятор прав?

g++ 4.9.2
clang++ 3.50
4b9b3361

Ответ 1

Цитаты, найденные @TartainLlama

Если гипотетическое создание шаблона сразу после его определения будет плохо сформировано из-за конструкции, которая не зависит от параметра шаблона, программа плохо сформирована; диагностика не требуется.

N4296 [temp.res]/8

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

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

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

N4296 [temp.dep]/1

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

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

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

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

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

Ответ 2

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

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

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

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

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