c – 通用lambda及其作为常量表达式的参数
作者:互联网
以下代码被GCC 7.2和clang 5.0.0接受,但被Microsoft VS 2017 15.5.0 Preview 5和Intel C编译器19拒绝:
struct S { };
constexpr int f(S)
{
return 0;
}
int main()
{
auto lambda = [](auto x)
{
constexpr int e = f(x);
};
lambda(S{});
}
微软:
<source>(12): error C2131: expression did not evaluate to a constant
英特尔:
<source>(12): error: expression must have a constant value
constexpr int e = f(x);
^
<source>(12): note: the value of parameter "x" (declared at line 10) cannot be used as a constant
constexpr int e = f(x);
^
如果我用f(decltype(x){})替换f(x),微软和英特尔都不会抱怨.我知道x不是一个常量表达式,但它不在f中使用.这可能是GCC和clang不抱怨的原因.
我猜微软和英特尔编译器在拒绝此代码方面是正确的.你怎么看?
解决方法:
从[expr.const]开始:
An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:
- […]
an lvalue-to-rvalue conversion unless it is applied to
- a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const object with a preceding initialization, initialized with a constant expression, or
- a non-volatile glvalue that refers to a subobject of a string literal, or
- a non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers to a non-mutable subobject of such an object, or
- a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;
[…]
在f(x)中,我们对x进行左值到右值的转换. x不是整数或枚举类型,它不是字符串文字的子对象,它不是用constexpr定义的对象,它的生命周期不是以f(x)的评估开始的.
这似乎使这不是一个核心的常数表达.
但是,正如Casey指出的那样,由于S是空的,因此其隐式生成的复制构造函数中的任何内容都不会实际触发此左值到右值的转换.这意味着此表达式中的任何内容实际上都没有违反任何核心常量表达式限制,因此gcc和clang在接受它时是正确的.这种解释对我来说似乎是对的. constexpr很有趣.
标签:c,lambda,language-lawyer,c14 来源: https://codeday.me/bug/20191008/1870602.html