如何防止无名称结构联合

How can I prevent a nameless structunion?

本文关键字:结构 何防止 无名      更新时间:2023-10-16

我正在构建一个矩阵数据有并集的类,但是,只有当我没有struct\union的名称时,我才能编译它。然而,有了更高级别的警告级别(视觉工作室上有四个),我会收到一个警告,说

warning C4201: nonstandard extension used : nameless struct/union

我调查了一下,似乎找不到防止这种情况发生的方法。无论如何,据我所知,可能会导致与其中一个或另一个的声明相关的不同编译器错误。如何在不禁用警告的情况下防止收到此警告并使其符合标准。

    union
    {
        struct
        {
            F32 _11, _12, _13, _14;
            F32 _21, _22, _23, _24;
            F32 _31, _32, _33, _34;
            F32 _41, _42, _43, _44;
        };
        F32 _m[16];
    };

(是的,我知道有可用的矩阵库。请不要把这变成"使用xxx库"的讨论,我这样做是为了扩展我对C++的知识。)

命名它似乎是最好的。C++中允许匿名联合,只是不允许结构。

union
{
    struct foo
    {
        F32 _11, _12, _13, _14;
        F32 _21, _22, _23, _24;
        F32 _31, _32, _33, _34;
        F32 _41, _42, _43, _44;
    } bar;
    F32 _m[16];
};

您可以使用引用/宏来允许在没有bar的情况下进行访问。

F32& _11 = bar._11;
F32& _12 = bar._12;

本质上与匿名结构相同。不过我并不真的推荐这个。如果可能,请使用bar._11


私有/公共(sorta):

struct mat 
{
  struct foo 
  {
    friend class mat;
    private:
      F32 _11, _12, _13, _14;
      F32 _21, _22, _23, _24;
      F32 _31, _32, _33, _34;
      F32 _41, _42, _43, _44;
  };
  union
  {
    foo bar;
    F32 _m[16];
  };
};

如果您只想在不更改实际代码的情况下禁用警告,那么您可以使用#pragma warning指令,如下所示:

#pragma warning(disable : 4201)

如果你想再次启用它,请使用:

#pragma warning(default : 4201)

有关附加参考,请参阅MSDN文档。

union
{
    struct // <- not named here
    {
        F32 _11, _12, _13, _14;
        F32 _21, _22, _23, _24;
        F32 _31, _32, _33, _34;
        F32 _41, _42, _43, _44;
    } AsStruct; // <- named here
    F32 AsArray[16];
};

我修复了它,没有给结构类一个名称,只给实例名称。

我见过的解决这一问题的最常见方法是重载类型的数组运算符。它相当特定于您发布的示例,但类似的方法也可以用于其他情况,其中无名称结构似乎是唯一的选项。

struct Mat {
   F32
    _11, _12, _13, _14,
    _21, _22, _23, _24,
    _31, _32, _33, _34,
    _41, _42, _43, _44;
  
    f32& operator[](uint32 ndx) { 
           return *reinterpret_cast<F32*>(&((&_11)[ndx])); 
     }
    const F32& operator[](uint32 ndx) const { 
           return *reinterpret_cast<const F32*>(&((&_11)[ndx])); 
    }
};

但是,在有矩阵的地方,通常有向量,这可以通过在向量类中定义类似于上面定义的数组运算符的数组运算符来对您有利。但是,不是在矩阵数组运算符中返回对F32的引用,而是返回对向量的引用。这里有一个例子:

struct vector4{
    F32 x,y,z,w;
    f32& operator[](uint32 ndx) { 
       return *reinterpret_cast<F32*>(&((&x)[ndx])); 
    }
    const F32& operator[](uint32 ndx) const { 
       return *reinterpret_cast<const F32*>(&((&x)[ndx])); 
    }
};
struct matrix4 {
    
   F32
    _11, _12, _13, _14,
    _21, _22, _23, _24,
    _31, _32, _33, _34,
    _41, _42, _43, _44;

    vector4& operator[](uint32 ndx) { return *reinterpret_cast<vector4*>(&((&_11)[ndx * 4])); }
    const vector4& operator[](uint32 ndx) const { return *reinterpret_cast<const vector4*>(&((&_11)[ndx * 4])); }
};

现在,代码可以更自然地编写,并且仍然高效,例如:

 F32 m00 = mymat4[0][0];

或:

 vector4 col0 = mymat4[0];

这种方法的最大缺点是矩阵现在必须是index[col][row]。这可以通过将运算符()添加到类中来解决。。。但那是另一回事。

您收到的警告不是关于内部结构,而是关于联合本身。试试这个:

union Mat    // <-------
{
    struct
    {
        F32 _11, _12, _13, _14;
        F32 _21, _22, _23, _24;
        F32 _31, _32, _33, _34;
        F32 _41, _42, _43, _44;
    };
    F32 _m[16];
};
Mat mat;
mat._11 = 42;
F32 x = mat._22;
mat._m[ 3 ] = mat._33;