通用lambda及其作为常量表达式的参数 [英] Generic lambda and its argument as constant expression

查看:212
本文介绍了通用lambda及其作为常量表达式的参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码被GCC 7.2和clang 5.0.0接受,但被Microsoft VS 2017 15.5.0 Preview 5和Intel C ++编译器19拒绝:

The following code is accepted by GCC 7.2 and clang 5.0.0, but is rejected by Microsoft VS 2017 15.5.0 Preview 5 and Intel C++ compiler 19:

struct S { };

constexpr int f(S)
{
    return 0;
}

int main()
{
    auto lambda = [](auto x)
    {
        constexpr int e = f(x);
    };

    lambda(S{});
}

Microsoft:

Microsoft:

<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(x)替换为f(decltype(x){}),则Microsoft和Intel都不会抱怨.我知道x不是常量表达式,但是在f内部未使用它.这可能就是为什么GCC和clang不抱怨的原因.

If I replace f(x) with f(decltype(x){}), both Microsoft and Intel do not complain. I understand that x is not a constant expression, but it is not used inside f. This is probably why GCC and clang do not complain.

我猜想Microsoft和Intel编译器在拒绝此代码方面是正确的.你觉得呢?

I guess that Microsoft and Intel compilers are correct in rejecting this code. What do you think?

推荐答案

来自 expr.const] :

表达式e是核心常量表达式,除非按照抽象机的规则对e的求值将对以下表达式之一求值:

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

  • 整数或枚举类型的非易失性glvalue,它引用具有先前初始化,使用常量表达式初始化的完整非易失性const对象,或者
  • 一个非易失性glvalue,它引用字符串文字的子对象,或者
  • 非易失性glvalue,它引用用constexpr定义的非易失性对象,或引用这种对象的不可变异子对象,或者
  • 文字类型的非易失性glvalue,指的是其寿命在e的求值内开始的非易失性对象;
  • 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)的评估开始的.

In f(x), we do an lvalue-to-rvalue conversion on x. x isn't of integral or enumeration type, it's not a subobject of a string-literal, it's not an object defined with constexpr, and its lifetime did not begin with the evaluation of f(x).

这似乎使它不是核心常量表达式.

That seems to make this not a core constant expression.

,由于S为空,因此其隐式生成的副本构造函数中的任何内容实际上都不会触发此左值到右值转换.这意味着该表达式中的任何内容实际上都没有违反任何核心常量表达式限制,因此gcc和clang在接受它方面是正确的.这种解释对我来说似乎是正确的. constexpr很有趣.

However, as Casey points out, since S is empty, nothing in its implicitly-generated copy constructor would actually trigger this lvalue-to-rvalue conversion. That would mean that nothing in this expression actually violates any of the core constant expression restrictions, and hence gcc and clang are correct in accepting it. This interpretation seems correct to me. constexpr is fun.

这篇关于通用lambda及其作为常量表达式的参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆