Именованные структуры в C ++ Unions - PullRequest
2 голосов
/ 14 июня 2011

В C ++ я пытаюсь создать специализированный точечный класс как объединение, например так:

union point
{
  struct { float x, y, z; };
  float val[3];
  float operator[](unsigned i) { return val[i]; }
};

Чтобы я мог получить доступ к точке в виде массива или нескольких точек для удобства чтения.

Однако, скажем, я хочу обобщить это немного:

template<unsigned n>
  union point
  {
    struct { float ???; };
    float val[n];
    float operator[](unsigned i) { return val[i]; }
  };

Что я могу поставить на ???? Я мог бы иметь x, x, y, x, y, z или x, y, z, w в зависимости от того, что такое n. Решение? Форвард декларации!

template<unsigned n>
  union point
  {
    struct coords;
    float val[n];
    float operator[](unsigned i) { return val[i]; }
  };

template<>
  struct point::coords<3>
  {
    float x, y, z;
  };

// ...

Но, похоже, это не работает. В соответствии с GCC 4.6 он компилируется, однако, всякий раз, когда я пытаюсь использовать члены, например так:

point<3> val;
val.x;

Я получаю ошибку:

error: ‘union point<3>’ has no member named ‘x’

Даже если я изменю val.x на val.coords::x, я все равно получаю ошибку:

error: ‘union point<3>::coords’ is not a base of ‘union point<3>’

Добавление using coords; в определении объединения тоже не помогло.

Есть ли способ сделать это в GCC 4.6? Есть ли другой способ сделать это? Это вообще возможно?

Ответы [ 2 ]

2 голосов
/ 14 июня 2011

Я бы предложил использовать variadic macro для определения ваших union<N> шаблонов.

template<unsigned int N>
union point; // declared and undefined

#define DECLARE_POINT(NUM, ...) \
template<> \
union point<NUM> \
{ \
  struct { float __VA_ARGS__; }; \
  float val[NUM]; \
}

#undef DECLARE_POINT

Сделав это, вы можете просто объявить / определить различные комбинации для координат (перед #undef в данном случае):

DECLARE_POINT(1, x);
DECLARE_POINT(2, x, y);
DECLARE_POINT(3, x, y, z);

, что эквивалентно

template<> union point<1> { struct { float x; }; float val[1]; };
template<> union point<2> { struct { float x, y; }; float val[2]; };
template<> union point<3> { struct { float x, y, z; }; float val[3]; };

Его можно использовать так же, как вы просили:

point<3> p;
p.z = 0;

Кроме того, вы можете поставить перекрестную проверку, используя некоторые хитрости шаблона (static_assert), чтобы проверить, что числовые аргументы (например, 1,2,3,...) соответствуют общему переданному аргументу (например, x,y,z,...).

1 голос
/ 14 июня 2011

Эта строка внутри вашего объединения:

struct coords;

forward-объявляет тип coords, но в вашем шаблонном объединении нет поля struct coords.

Кроме того, только членыанонимные структуры могут быть доступны как поля верхнего уровня объединения.Например:

union foo {
    struct { // anonymous struct
        short i;
        short j;
    };
    int k;
};

foo f;
// it's possible to access the fields of the anonymous struct as if they were
// direct members of the union
f.i = 4;
f.j = 8;
std::cout << f.k;

Я не уверен, что вы сможете сделать это, если будете специализировать только внутренний тип struct.

Однако это работает:

template<unsigned n>
union point;

template<>
union point<2> {
    struct { float x, y; };
    float val[2];
};

template<>
union point<3> {
    struct { float x, y, z; };
    float val[3];
};

Хотя есть ряд недостатков;главное в том, что вам придется переопределять operator[] для каждой версии point.

Я знаю, как использовать шаблоны, но я не бог шаблона, поэтому не исключено, чтохитрый трюк существует.

...