【问题标题】:Inspect inactive member of a union with common initial sequence in constexpr expression在 constexpr 表达式中检查具有公共初始序列的联合的非活动成员
【发布时间】:2020-09-28 07:55:38
【问题描述】:

第 12.3.1 点中的 C++ 标准说:

如果标准布局联合包含多个共享公共初始序列的标准布局结构,并且此标准布局联合类型的对象的非静态数据成员处于活动状态并且是标准布局之一结构,允许检查任何标准布局结构成员的公共初始序列;

但以下代码无法在任何主要编译器上编译 (https://godbolt.org/z/3jM1co):

struct type {
    union {
        int a;
        int b;
    };

    constexpr type(int n) : a(n) {}
};

constexpr int fun(int n) {
    type t(n);

    return t.b;
}

constexpr int res = fun(5);

为什么代码不能编译(我相信这里所有的编译器都没有错)?此代码应满足访问联合的技术非活动成员的条件(标准布局,通用初始序列)。当constexpr 关键字被删除时,这段代码编译没有问题。

【问题讨论】:

  • 联合不包含任何标准布局结构,只有简单类型。将a 和b 制作成结构。删除 constexpr 后,代码具有未定义的行为。
  • 没关系。当用 struct 包装 a 和 b 时,会出现同样的错误。

标签: c++ language-lawyer constexpr unions


【解决方案1】:

您引用的文本是正确的,但是在 constexpr 上下文中访问联合的非活动成员有额外的限制。特别是你违反了这个rule:

表达式 E 是核心常量表达式,除非 E 的求值遵循抽象机 ([intro.execution]) 的规则,将求值以下之一:

左值到右值的转换,应用于引用联合或其子对象的非活动成员的左值;


请注意,您可以在 constexpr 上下文中更改联合的活动成员,因此您可以这样做:

constexpr int fun(int n) 
{
    type t(n);
    t.b = t.a;    // t.b is now the active member
    return t.b;   // ok, reading from active member is fine
}

我相信这仅允许从 c++20 开始:demo。

相关的rule是这样的:

表达式 E 是核心常量表达式,除非 E 的求值遵循抽象机 ([intro.execution]) 的规则,将求值以下之一:

调用隐式定义的复制/移动构造函数或复制/移动赋值运算符,用于其活动成员(如果有)是可变的联合,除非联合对象的生命周期开始于 E 的评估中;

(重点是我的)。由于t 的生命周期在fun 的评估中开始,因此这是允许的。

【讨论】:

  • 我明白原因了。但对我来说这很不幸,建议的解决方法可能无法解决我的问题。
  • @Bargor 我实际上并没有提出修复建议,只是指出了问题所在。但是,修复确实似乎没问题。它有什么问题?它似乎与原始代码具有相同的语义(并且有效)。
猜你喜欢
  • 1970-01-01
  • 2018-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 2015-01-22
  • 1970-01-01
相关资源
最近更新 更多