带有结构成员的 C++ 联合结构适用于 Clang 和 MSVC,但不适用于 GCC

问题描述 投票:0回答:2

我正在尝试定义一个联合结构,其中一些结构和原始成员在内存中与一个简单的数组重叠。这在 Clang 和 MSVC 中完美运行,但不能用 GCC (G++) 编译。

struct Vector3 {
    float x;
    float y;
    float z;
    Vector3() {}
};

struct Plane {
    union {
        struct {
            Vector3 normal;
            float d;
        };
        float elements[4] = { 0 };
    };
    Plane() {}
};

使用 GCC,我收到此编译错误:

<source>:11:33: error: member 'Vector3 Plane::<unnamed union>::<unnamed struct>::normal' with constructor not allowed in anonymous aggregate
   11 |                         Vector3 normal;
      |                                 ^~~~~~

我给出的代码示例是有效的 C++ 吗?为什么在匿名聚合中不允许使用它,但在命名聚合中却似乎可以工作?我可以对其进行哪些更改以使其在 GCC 中工作,而不涉及删除构造函数或在联合中命名结构?它在 Clang 和 MSVC 中有效但在 GCC 中无效的原因是什么?

如果我用

struct {
替换
struct Named {
有没有办法让它工作?

c++ gcc struct language-lawyer unions
2个回答
2
投票

我给出的代码示例是有效的 C++ 吗?

不。不允许使用匿名结构,因此程序格式错误。

它在 Clang 和 MSVC 中工作的原因是什么

当格式错误的程序运行时,通常是由于语言扩展造成的。

但不在海湾合作委员会

类似语言扩展的实现可能存在差异。当然,这种扩展的限制不是由语言定义的。由于此扩展基于 C 语言功能,因此它不一定适用于构造函数等 C++ 功能,这是有道理的。

我可以对其进行哪些更改以使其在 GCC 中工作,而不涉及删除构造函数或在联合中命名结构?

使程序明确定义 C++ 的唯一方法是不使用匿名结构。


额外答案:如果您希望在写信给

elements
normal
后阅读
d
,反之亦然,那么这也是不允许的。程序的行为是未定义的。


如何使用重叠内存创建不同名称的属性?除了 Plane 之外,我还想在其他结构中执行此操作,例如通过 3D Basis 结构 columns[3] ,其中数组的成员也可以通过 x、y 和 z 访问。

C++在这方面有局限性,不能用简单的方法来完成。它可以通过依赖运算符重载来完成,但有点复杂:

template<class T, std::size_t size, std::size_t i>
struct Pun {
    T a[size];
    static_assert(i < size);
    auto& operator=(T f) { a[i] = f; return *this; }
    operator       T&()        &   { return a[i]; }
    operator const T&()  const &   { return a[i]; }
    operator       T ()        &&  { return a[i]; }
    T      * operator&()       &   { return a+i ; }
    T const* operator&() const &   { return a+i ; }
};

template<class T, std::size_t size>
struct Pun<T, size, size> {
    T a[size];
    using A = T[size];
    operator       A&()        &   { return a; }
    operator const A&()  const &   { return a; }
    A      * operator&()       &   { return &a; }
    A const* operator&() const &   { return &a; }
};

union Plane {
    Pun<float, 4, 4> elements;
    Pun<float, 4, 0> x;
    Pun<float, 4, 1> y;
    Pun<float, 4, 2> z;
    Pun<float, 4, 3> d;
};

允许读取

Plane
的非活动成员,因为所有元素都是布局兼容的结构。
x
等可以隐式转换为float,
elements
可以隐式转换为float数组。


0
投票

仅在使用 gnu++98 (1998) 时无法从 Xcode 进行编译。它在 gnu++11 标准中编译得很好,并且

根本问题是您提供的默认 ctor 非常重要

如果从

Vector3
结构中删除构造函数,即使在 gnu++98 中也能正常编译

struct Vector3 {
  float x;
  float y;
  float z;
  //Vector3() {} // remove this line to compile
};
© www.soinside.com 2019 - 2024. All rights reserved.