为什么联合静态成员不存储为联合?

Why union static members not stored as a union?

在 C++ 中,union 可以包含静态成员,在 classes 的情况下,属于 class,因此对所有对象都是通用的。

union U
{
   long l;
   int i;
   static long sl;
   static int si;
};

int U::si;
long U::sl;

所有联合静态成员都存储在与非静态成员存储相似的同一地址是合乎逻辑的。但事实并非如此。一个简单的例子表明,静态成员存储在不同的地址下,可以包含 independent 值。

int main()
{
   U u;
   u.si = 10;
   u.sl = 50;

   std::cout << "Non-static members adresses: " << &u.i << " " << &u.l << std::endl;
   std::cout << "Static members adresses: " << &u.si << " " << &u.sl << std::endl;
   std::cout << "Static members values: " << u.si << " " << u.sl << std::endl;
   return 0;
}

输出:

Non-static members adresses: 006FF8EC 006FF8EC
Static members adresses: 00AEB144 00AEB140
Static members values: 10 50

我不明白为什么将独立值存储留在联合中。我认为这是一种误导,没有任何意义。然而,在我看来,这是有原因的。 union 静态成员的用途是什么?

联合 class 一次最多包含一个数据成员 [basic.compound]p1.6 [class]p7 [class.union],并且它们的静态数据成员没有特殊规则 w.r.t。 class 类型的其余部分(即 classstruct)。

因此,静态数据成员的行为与所有 classes 中的行为相同。

如果你想要一个静态数据成员,它是几种类型的联合,你可以这样做:

union U {
    long l;
    int i;

    union {
        long l;
        int i;
    } static s;
};

decltype(U::s) U::s;

// They are the same indeed
static_assert(&U().s.l == &U().s.l);

您需要通过 s 引用元素,例如不过 s.l 而不是 sl

你可以从两个角度来看。

C++ 视角:

工会首先是class。它的用途不同于 class,但它由 class 是什么来告知。

联合是一个class,它的任何一个类型都只有一个子对象处于活动状态。为此,它改变了联合的成员子对象的工作方式。这也是联合不能有 base class 子对象的部分原因。

静态数据成员不是成员子对象,因此它们在联合中的配置应该与它们在非联合中的配置没有区别class。

此外,C++ 中类型的静态成员实际上只是函数和对象名称的作用域机制。它们实际上仍然是全局的,但它们可以是私有的和隐藏的,并且必须以它们的类型名称为前缀才能使用它们。

联合的静态数据成员的行为与 class 的静态数据成员的行为没有任何区别。

C++ 必须与 C 兼容的观点:

C 中存在联合,因此 C++ 也必须有联合。但是联合很难在 C++ 对象模型中定义,使用起来很痛苦,还有很多其他问题。因此,您可以将联合视为 C++ 需要但不愿处理的东西。那你是怎么对付他们的呢?

在处理 C 联合的工作方式时,您让联合像 C 一样工作。 C 中没有静态成员这样的东西,因此没有 C 代码期望组合静态联合成员。因此......不要将它们结合起来。如果用户真的需要一个静态成员,它是某些类型集的联合体,他们可以轻松地创建一个联合体并创建该类型的单个静态成员。

所以用户不会因为使静态成员不同而失去任何表达能力。