C ++ 11 static_assert и создание шаблона - PullRequest
48 голосов
/ 09 марта 2011

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

template <int I>
void sa() { static_assert(0,"Hello."); }

int main(int argc, char *argv[]) { return 0; }

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

Ответы [ 6 ]

50 голосов
/ 09 марта 2011

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

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

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

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

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

8 голосов
/ 09 марта 2011

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

4 голосов
/ 09 марта 2011

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

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

Те же слова встречаются в стандарте C ++ 03.

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

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

3 голосов
/ 14 марта 2012

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

template<typename T> 
bool dependentFalse<T>()
{
    return false;
}

template<typename T>
Foo foo()
{
    static_assert(dependentFalse<T>(), "this template shouldn't be instantiated");
}
2 голосов
/ 09 марта 2011

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

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

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

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

0 голосов
/ 09 марта 2011

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

template <int I>
void sa()
{
    static_assert(0,"Hello.");
}

template <>
void sa<0>()
{
}

int main(int argc, char *argv[]) { return 0; }

Эта программа не:

template <int I>
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 <iostream>

using ::std::cout;

template <int I>
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, и если это изменилось, он не может скомпилироваться так, как должен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...