Правильно ли это сообщение об ошибке: аргумент шаблона не-типа не является постоянным выражением
Следующая программа компилируется с GCC 5.2, но не с clang 3.6:
constexpr bool flag();
template <bool b = flag()>
constexpr bool test()
{
return b;
}
int main()
{
}
Сообщение об ошибке, которое я получаю с clang:
main.cpp:3:20: error: non-type template argument is not a constant expression
template <bool b = flag()>
^~~~~~
main.cpp:3:20: note: undefined function 'flag' cannot be used in a constant expression
main.cpp:1:16: note: declared here
constexpr bool flag();
^
main.cpp:4:16: error: no return statement in constexpr function
constexpr bool test()
^
Мой вопрос: кто прав? Или, другими словами: Является ли программа плохо сформированной?
Ответы
Ответ 1
Я бы сказал, что clang прав:
Из стандарта:
[temp.param] 14.1 # 9
9 Шаблон-аргумент по умолчанию - это шаблон-аргумент (14.3), указанный после = в параметре шаблона. [...]
И [temp.arg.nontype] 14.3.2
1 Аргумент шаблона для не-type template-parameter должен быть преобразованным константным выражением (5.20) типа параметра шаблона.
И [expr.const] 5.20
2 Условное выражение e является выражением основной константы, если оценка e, следуя правилам абстрактной машины (1.9), не будет оценивать одно из следующих выражений:
[...]
(2.3) - вызов функции undefined constexpr или конструктора undefined constexpr;
Так как flag()
объявлен, но не определен, он не является постоянным выражением и 14.3.2 нарушен.
Ответ 2
В соответствии с ISO С++ 14 Стандарт 5.19.2:
Условное выражение e является выражением постоянной константы, оценка e, следуя правилам абстрактной машины (1.9), будет оценивать одно из следующих выражений:
- this (5.1.1), за исключением функции constexpr или конструктора constexpr, который оценивается как часть e;
- вызов функции, отличной от конструктора constexpr для класса literal, функции constexpr или неявного вызова тривиального деструктора (12.4) [Примечание: разрешение перегрузки (13.3) применяется как обычно - примечание конца);
- вызов функции undefined constexpr или конструктора undefined constexpr;
- (...) Blockquote
Результат любого вызова функции constexpr, сделанного до его определения, не является постоянным выражением.
Наконец, кажется, что это ошибка GCC.