4

Из того, что я собираю из this answer, результат функции constexpr не является константным выражением, если функция еще не объявлена. Что меня удивляет, это следующий фрагмент кода:Вложенные вызовы `constexpr` перед определением в контексте константного выражения

constexpr int f(); 

constexpr int g() { 
    return f(); 
} 

constexpr int f() { 
    return 42; 
} 

int main() { 
    constexpr int i = g(); 
    return i; 
} 

Это компилируется без проблем и работает. Перемещение f в определении основных триггеров error: 'constexpr int f()' used before its definition, как и следовало ожидать.

Я предполагаю, что он работает, потому что f был определен до вызова g, поэтому оба вызова являются постоянными выражениями.

Почему и g(), по-видимому, постоянные выражения, хотя f не определяется, когда он вызывается g? Как это описывается Стандартом?

Я тестировал это на GCC 6.1.0 и Clang 3.8.0 от Coliru.

+1

5.20/(2.3): "if ... invocation undefined' constexpr' function "? –

+0

Я думаю, что мы должны подчеркнуть тот факт, что функция 'constexpr' должна иметь определение только после того, как она используется« odr-used ». Поэтому, даже если 'f()' не имеет определения в 'g()', компилятор может угадать тело 'g()' с помощью простого объявления, но на самом деле вызывать 'g()', вам нужно определение 'f()', потому что вызов функции считается «odr-use». Итак, да, данный ответ действительно, но я думаю, что это то, что ОП было смущено о – KABoissonneault

+3

См. [CWG2166] (http://wg21.link/CWG2166). –

ответ

0

Как связаться с T.C. в his comment, это подлежит defect report.

Согласно 5.20 [expr.const] пуль 2.3, выражение является константой выражения, если (среди других причин) не будет оценивать

  • собой вызов неопределенной функции constexpr или неопределенный constexpr конструктор;

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

Это дает понять, что пример хорошо сформирован и действительно должен работать, как и ожидалось, пока f определяется перед вызовом g.

0

Перед использованием не обязательно определять constexpr. Однако результатом вызова его перед его определением является не constexpr. Следовательно, компилятор справедливо жалуется, потому что вы пытаетесь инициализировать переменную constexpr с не константным выражением.

§5.20/p2 константные выражения [expr.const] (курсив мой):

Условное выражение-е является постоянным выражением сердечника, если только оценки е, следуя правилам абстрактной машины (1.9), бы оценить одно из следующих выражений:

...

(2.3) - вызов неопределенной функции constexpr или undefined constexpr constructor;

+0

Извините, я думаю, что мой вопрос был не ясен. Я спрашиваю, почему вызов * является * фактически постоянным выражением, хотя 'f' не определен в той точке, которую он вызывается? – Quentin

+0

Ваша цитата может быть прочитана как разрешающая и запрещающая код OP, так и непонятно, как вы ее читаете, и неясно, правильное ли это чтение (в зависимости от того, что это такое). – hvd

+1

Учитывая ваше редактирование: это оставляет важный вопрос, который еще остается без ответа. Имеет ли [dcl.constexpr] p5 («Для несимвольной, не дефолтной функции constexpr [...], если нет значений аргумента, так что вызов функции [...] может быть оцененным подвыражением (5.19), программа плохо сформирована, не требуется диагностика. ») позволяют компилятору немедленно выпустить сообщение об ошибке после определения' g'? До определения 'f' нет значений аргументов, чтобы сделать результат оценки' g() 'постоянным выражением. – hvd

Смежные вопросы