2016-02-26 2 views
5

Рассмотрим следующий код (available on gcc.godbolt.org):Использование лямбда в `constexpr` функции в не `constexpr` контексте: лязг против НКУ

template <typename TF> 
constexpr auto fn_x(TF f) 
{ 
    return f(); 
} 

constexpr auto get_x() 
{ 
    return fn_x([]{ return 0; }); 
} 

int main() 
{ 
    auto res = get_x(); 
} 

Он компилирует под 5.3.x г ++ и новее (включая g ++ 6.xx).

Это не компилируется под лязгом ++ 3.7.x и новее со следующей ошибкой:

error: constexpr function never produces a constant expression [-Winvalid-constexpr] 
constexpr auto get_x() 
      ^
note: subexpression not valid in a constant expression 
     return fn_x([]{ return 0; });       

Возможное решение сделать код компилировать как с НКУ и лязгом использует «слой косвенности» с decltype, также избавляясь от constexpr в функции, где определена лямбда: gcc.godbolt.org link.

Какой компилятор здесь указан в соответствии со стандартом?

+0

В любом случае, возможно, более релевантный вашему вопросу: какой-либо из компиляторов, с которыми вы тестируете, утверждает, что 'get_x()' может использоваться в постоянном выражении? Если нет, возникает вопрос: «Я могу добавить' constexpr' к функциям, которые никогда не могут использоваться в постоянных выражениях? » – hvd

+0

@hvd: Что касается точек с запятой, я всегда компилирую настоящий код с помощью '-Wpedantic', который информирует меня об ошибке. Я привык писать лямбда-тяжелый код ('auto l = [] {...};'), поэтому иногда мой мозг автоматически добавляет точку с запятой в конце функции. –

+0

@hvd Это действительно C++ 11 - ';' является * пустой декларацией *. См. [CWG 569] (http://wg21.link/cwg569). –

ответ

6

Оба компилятора согласны с тем, что get_x() не может использоваться в постоянном выражении. Вы можете сказать, изменив auto res = get_x(); на constexpr auto res = get_x();, где GCC отклонит его в равной степени.

Что касается его обнаружения во время определения функции, как лязг делает, а не на функции использовать как GCC делает, как разрешено: (курсив мой)

7.1.5 The constexpr specifier [dcl.constexpr]

5 For a non-template, non-defaulted constexpr function or a non-template, non-defaulted, non-inheriting constexpr constructor, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression (5.19), the program is ill-formed; no diagnostic required. [...]

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

+0

Я унижен! :) – SergeyA

+1

В стороне, отсутствие поддержки 'constexpr' от lambdas - это немного недостающая функция на C++. [Здесь] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4487.pdf) является таким предложением. – Yakk