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

Using a lambda in a `constexpr` function in a non-`constexpr` context: clang vs gcc

本文关键字:constexpr clang gcc lambda vs 函数 上下文 在非      更新时间:2023-10-16

请考虑以下代码(在 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();
}

它在 g++ 5.3.x 及更高版本(包括 g++ 6.x.x)下编译。

它无法在 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; });                        

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

根据标准,哪个编译器是正确的?

两个编译器都同意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),则程序格式不正确;无需诊断。[...]

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