在非`constexpr`上下文中的`constexpr`函数中使用lambda:clang vs gcc

Vit*_*meo 5 c++ lambda language-lawyer constexpr c++14

请考虑以下代码(可在gcc.godbolt.org上获得):

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();
}
Run Code Online (Sandbox Code Playgroud)

它在g ++ 5.3.x和更新版本(包括g ++ 6.xx)下编译.

它不能在clang ++ 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; });                        
Run Code Online (Sandbox Code Playgroud)

使用gcc和clang编译代码的可能解决方案是使用"间接层" decltype,同时摆脱constexpr定义lambda的函数:gcc.godbolt.org链接.

根据标准,这里的编译器是否正确?

小智 6

两个编译器都是一致的,get_x()不能用于常量表达式.您可以通过更改auto res = get_x();来确定constexpr auto res = get_x();,GCC将平等拒绝它.

至于在功能定义时检测它像clang一样,而不是像gcc那样在功能上使用,两者都是允许的:(强调我的)

7.1.5 constexpr说明符[dcl.constexpr]

5对于非模板,非默认constexpr函数或非模板,非默认,非继承constexpr构造函数,如果不存在参数值,则调用函数或构造函数可以是核心常量表达式的计算子表达式(5.19),该计划格式不正确; 无需诊断.[...]

在一般情况下,不可能可靠地检测是否存在允许将结果用于常量表达式的函数调用,这就是诊断是可选的原因.