Как я могу предотвратить безымянную структуру\объединение?

Я создаю класс, который имеет объединение для своих матричных данных, однако я могу его скомпилировать только тогда, когда у меня нет имени для структуры\объединения. Однако с уровнем предупреждения более высокого уровня (четыре в визуальной студии) я буду предупреждать, говоря

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++».)


person mmurphy    schedule 13.01.2012    source источник
comment
Можете ли вы показать будущим читателям свой код, который называет структуру и не компилируется?   -  person Keith Thompson    schedule 13.01.2012


Ответы (5)


Именование кажется лучшим. В 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, если это возможно.


Частный/публичный (типа):

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];
  };
};
person Pubby    schedule 13.01.2012
comment
Кажется, это так. Хотя это и не является частью первоначального вопроса, есть ли способ сделать bar защищенным\приватным, но при этом разрешить _m быть общедоступным? - person mmurphy; 13.01.2012
comment
Ок, интересно. И последнее, я изучил использование ссылок (я хотел бы использовать _11, если это возможно, без префикса). Как можно объявить ссылку в классе? Что-то вроде F32& _11 = bar._11; нельзя просто быть на публике:. - person mmurphy; 13.01.2012

Если все, что вы хотите сделать, это отключить предупреждение без изменения фактического кода, вы можете использовать директиву #pragma warning следующим образом:

#pragma warning(disable : 4201)

Если вы хотите снова включить его, используйте:

#pragma warning(default : 4201)

Дополнительные сведения см. в документации MSDN. .

person codekiddy    schedule 13.01.2012
comment
Извините, я должен был быть более конкретным и сказать, не просто отключив предупреждение - person mmurphy; 13.01.2012

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

Я исправил это, не давая имени классу структуры, только имя экземпляра.

person Dominic Birmingham    schedule 29.08.2018

Самый распространенный способ решения этой проблемы — перегрузка оператора массива для типа. Это довольно специфично для опубликованного вами примера, но аналогичные методы можно использовать в других ситуациях, когда безымянная структура кажется единственным вариантом.

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

or:

 vector4 col0 = mymat4[0];

Самый большой недостаток этого подхода заключается в том, что матрица теперь должна иметь индекс [столбец][строка]. Это можно решить, добавив в класс оператор()... но это уже другая история.

person pmw1234    schedule 16.05.2021

У вас есть это предупреждение не о внутренней структуре, а о самом объединении. Попробуй это:

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;
person borisbn    schedule 19.11.2014