Правильно ли это сообщение об ошибке: аргумент шаблона не-типа не является постоянным выражением

Следующая программа компилируется с 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.