static_assert зависит от нетипичного параметра шаблона (различное поведение в gcc и clang)

template <int answer> struct Hitchhiker {
static_assert(sizeof(answer) != sizeof(answer), "Invalid answer");
};

template <> struct Hitchhiker<42> {};

При попытке отключить общее создание шаблона с помощью static_assert Я обнаружил, что приведенный выше код в clang генерирует ошибку подтверждения, даже если шаблон не создан, а gcc генерирует ошибку подтверждения только при создании экземпляра Hitchhiker с параметром, отличным от 42,

Повозившись, я обнаружил, что это утверждают:

template <int answer> struct Hitchhiker {
static_assert(sizeof(int[answer]) != sizeof(int[answer]), "Invalid answer");
};

template <> struct Hitchhiker<42> {};

ведет себя одинаково на обоих компиляторах: утверждение включается только тогда, когда создается общий шаблон.

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

g++ 4.9.2
clang++ 3.50

24

Решение

Цитаты найдены @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 сбой) допустимое поведение компилятора. Отсутствует проблема допустимого поведения компилятора. Поведение программы, составленной из плохо сформированной, не требующей диагностики программы, не определено стандартом: это неопределенное поведение. Носовые демоны разрешены.

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

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

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

14

Другие решения

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

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

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

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

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

По вопросам рекламы [email protected]