C ++ 11 static_assert и создание шаблона

В C ++ 11, если операция static_assert в шаблоне зависит от того, был ли этот экземпляр создан или нет? Например, со следующим кодом

template  void sa() { static_assert(0,"Hello."); } int main(int argc, char *argv[]) { return 0; } 

GCC 4.5.0 не выполнит это утверждение и произведет «Привет». сообщение. С другой стороны, компилятор Digital Mars 8.42n не дает сообщений.

GCC правильный, и другой компилятор тоже прав. См. 14.6p8 в спецификации

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

Поэтому компилятор может отклонить следующие

 template void f() { static_assert(0, "may trigger immediately!"); static_assert(sizeof(T) == 0, "may trigger immediately!"); } 

Если вы хотите пойти в безопасное место, вам необходимо его организовать, чтобы компилятор не смог узнать, пока не будет установлено, будет ли логическое выражение истинным или ложным. Например, получите значение getvalue::value , причем getvalue является шаблоном classа (можно было бы его специализировать, поэтому компилятор не может знать булевское значение уже).

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

Проект C ++ 0x ( N3242 ) говорит в 14.6p8:

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

Эти же слова появляются в стандарте C ++ 03.

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

Поскольку диагностика не требуется, компилятор может скомпилировать программу, если шаблон не создан. Конечно, если он создается, программа плохо сформирована, и требуется диагностика.

Я использовал вспомогательную функцию, чтобы сделать ложную зависимость от параметра шаблона:

 template bool dependentFalse() { return false; } template Foo foo() { static_assert(dependentFalse(), "this template shouldn't be instantiated"); } 

Это раздел 14.6.2 в стандарте C ++.

Ваш static_assert связан с поддержкой привязки независящих имен при первоначальном анализе шаблона . Компилятор Digital Mars Compiler в настоящее время не поддерживает привязные независимые имена. GCC 4.5.0 поддерживает привязку не зависящих имен.

Если ваше выражение не зависит от параметров шаблона, тогда такое выражение известно при первоначальном анализе шаблона. Компилятор должен показать сообщение об ошибке. GCC 4.5.0 делает это.

Замените свой 0 в static_assert на I*I < 0 , для примера, и вы получите зависимое имя. Сообщение об ошибке появится только для случая незакрепленного шаблона.

Эта программа генерирует ошибку:

 template  void sa() { static_assert(0,"Hello."); } template <> void sa<0>() { } int main(int argc, char *argv[]) { return 0; } 

Эта программа не выполняет:

 template  void sa() { static_assert(I != 0,"Hello."); } template <> void sa<0>() { } int main(int argc, char *argv[]) { return 0; } 

Это не имеет никакого смысла для этого. Поэтому я пришел к выводу, что g ++ 4.5 должен быть ошибкой, если он запускает static_assert в незакрепленном шаблоне.

И еще более тревожная, следующая программа печатает I == 1 .

 #include  using ::std::cout; template  void sa() { cout << "I == " << I << '\n'; static_assert(I != 0,"Hello."); } template <> void sa<0>() { cout << "I == " << 0 << '\n'; } int main(int argc, char *argv[]) { sa<1>(); return 0; } 

Это указывает на серьезную ошибку в том, как gcc обрабатывает static_assert .

Редактировать : О, хорошо. В моей программе есть ошибка. Он должен читать I == 0 , а не I != 0 , и если это было изменено, оно не скомпилируется так, как должно.

  • C ++ metafunction, чтобы определить, является ли тип вызываемым
  • Является ли ключевое слово 'override' просто проверкой переопределенного виртуального метода?
  • Что такое hash-функция по умолчанию, используемая в C ++ std :: unordered_map?
  • Ошибка компоновщика C ++ с classом static constexpr
  • Получить статус std :: future
  • Реализация операторов сравнения через «tuple» и «tie» - хорошая идея?
  • C ++ 11 - static_assert в функции constexpr?
  • Как вызвать функцию во всех вариационных шаблонных аргументах?
  • boost :: asio + std :: future - Нарушение прав доступа после закрытия сокета
  • Как разбирать строку даты в c ++ 11 std :: chrono time_point или подобное?
  • Использование вектора в качестве буфера без его инициализации при изменении размера ()
  • Давайте будем гением компьютера.