How can I prevent a nameless struct\union?
Asked Answered
F

5

9

I am building a class that has a union for its matrix data, however, I can only get it compile when I do not have a name for the struct\union. However, with a higher level warning level (four on visual studio) I will a warning saying

warning C4201: nonstandard extension used : nameless struct/union

I looked into it, and I don't seem to be able to find a way to prevent this. Anyway possible that I know of will cause a different compiler error related to the declaration of one or the other. How can I prevent getting this warning and make it conform to standards, without just disabling the warning.

    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];
    };

(Yes, I know there is matric libraries available. Please do not turn this into a "use xxx library" discussion, I am doing this to expand my knowledge of C++".)

Flashing answered 13/1, 2012 at 4:24 Comment(1)
For the benefit of future readers, can you show your code that names the struct and doesn't compile?Mikkanen
S
10

Naming it seems best. Anonymous unions are allowed in C++, just not structs.

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];
};

You can use references/macros to allow access without bar.

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

Essentially the same as an anonymous struct. I don't really recommend this though. Use bar._11 if possible.


Private/public (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];
  };
};
Solvency answered 13/1, 2012 at 4:41 Comment(2)
That seems to do it. Although not part of the original question, is there a way to make bar protected\private while still allowing _m to be public?Flashing
Oh ok, interesting. One last thing, I looked into using references (I would like to use _11 if possible, without the prefix on it). How could the reference be declared in the class? Something such as "F32& _11 = bar._11;" can't just be in public:.Flashing
G
6

If all you want to do is to disable the warning without changing the actual code then you can use #pragma warning directive like so:

#pragma warning(disable : 4201)

If you want to reenable it again use:

#pragma warning(default : 4201)

For addition reference, see MSDN documentation.

Gryphon answered 13/1, 2012 at 4:49 Comment(3)
Sorry, I should have been more specific and said without just disabling the warningFlashing
Despite anonymous being structs "technically undefined in the C++ spec" and all, the reality is that all the major compilers support anonymous structs because C itself supports them, and C++ needs to be able to include header files from C. So this is the answer I went with in my projects.Alberta
Adding to this that to re-enable the warning, you should surround the region with #pragma warning(push) and #pragma warning(pop) to ensure the warning state is correctly restored to its previous setting. This allows you to localize warning changes to one region.Monteverdi
J
2
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];
};

I fixed it without giving the struct class a name, just the instance name.

Jocosity answered 29/8, 2018 at 21:27 Comment(0)
I
0

The most common way I have seen to address this is by overloading the array operator for the type. It is fairly specific to the example you posted, but similar methods can be used in other situations where a nameless struct seems like the only option.

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])); 
    }
};

But, where there is a matrix there are usually vectors, this can be used to your advantage by defining the array operator in the vector class similar to the array operator defined above. But instead of returning a reference to a F32 in the matrix array operator, return a reference to a vector. Here is an example:

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])); }
};

Now code can can be written much more naturally and is still efficient, for example:

 F32 m00 = mymat4[0][0];

or:

 vector4 col0 = mymat4[0];

The biggest drawback of this approach is that the matrix now has to be index [col][row]. This can be resolved by adding the operator() to the class...but thats another story.

Indescribable answered 16/5, 2021 at 17:8 Comment(0)
C
-2

You have this warning not about the inner struct but about union itself. Try this:

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;
Che answered 19/11, 2014 at 11:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.