2016-02-26 86 views
5

考虑下面的代码available on gcc.godbolt.org使用在非`constexpr`上下文`constexpr`功能的λ:铛VS GCC

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; });       

的可能解决方案,以使代码编译GCC和铛使用“间接层”与decltype,也摆脱在定义lambda的函数constexprgcc.godbolt.org link

根据标准哪个编译器在这里是正确的?

+0

无论如何,也许与你的问题更相关:做任何你测试的编译器声明'get_x()'可以用在一个常量表达式中?如果不是,你的问题是“我允许将'constexpr'添加到永远不能用于常量表达式的函数吗?” – hvd

+0

@hvd:关于分号,我总是用'-Wpedantic'编译真实的代码,这会告诉我这个错误。我习惯于编写lambda-heavy代码('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. [...]

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

+0

我很羞辱! :) – SergeyA

+1

另一方面,缺乏lambda的'constexpr'支持在C++中有一点缺失。 [这里](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4487.pdf)就是这样一个建议。 – Yakk