enable/disable 的匿名结构

Anonymous struct with enable/disable

我有以下向量 class(空间向量,而不是数组):

template<typename T0, size_t S, typename = typename std::enable_if<std::is_arithmetic<T0>::value && (S > 1 && S < 5)>::type>
struct Vec
{
    using value_type = T0;
    using vector_type = Vec<T0, S>;
    using array_type = std::array<T0, S>;
    using index_type = size_t;
    using size_type = size_t;

    enum { num_components = S };

    array_type v;
};

,这样我就可以制作一个包含 2、3 或 4 个元素的向量类型:

    template<typename T0>
    using Vec2 = Vec<T0, 2>;

    template<typename T0>
    using Vec3 = Vec<T0, 3>;

    template<typename T0>
    using Vec4 = Vec<T0, 4>;

Access 的形式为 v[0]、v[1] 等(为简洁起见,我不包括 [] 运算符重载)。有时我更喜欢 x、y 等等,但不想要额外的“。”从命名联合中的结构。所以使用Visual Studio 2013的非标准"feature",尝试使用匿名联合,只启用S(维度)为2、3或4时的值,如下:

    template<typename T0, size_t S, typename = typename std::enable_if<std::is_arithmetic<T0>::value && (S > 1 && S < 5)>::type>
    struct Vec
    {
        using value_type = T0;
        using vector_type = Vec<T0, S>;
        using array_type = std::array<T0, S>;
        using index_type = size_t;
        using size_type = size_t;

        enum { num_components = S };

        union
        {
            array_type v;

            template<typename = typename std::enable_if<S == 2>::type>
            struct
            {
                value_type x, y;
            };

            template<typename = typename std::enable_if<S == 3>::type>
            struct
            {
                value_type x, y, z;
            };

            template<typename = typename std::enable_if<S == 4>::type>
            struct
            {
                value_type x, y, z, w;
            };
        };
    };

不幸的是,这给了我以下错误:

**error C2332: 'struct' : missing tag name**

我想在某种程度上是这样。有什么办法可以实现我在这里尝试的目标吗?我确信匿名结构的 enable/disable 几乎肯定会给编译器带来偏头痛。如果我当然给结构命名,我可以像这样使用匿名联合。

为什么您决定 std::array 和 struct{ T x, T y, ... T} 的内存布局相同?仅当您使用 #pragma pack 将 class 的对齐设置重置为 1 时才能达到它。对于其他人来说,对齐方式是不可预测的。

您想 class

  1. 通过 .x、.y 等数据成员选择器提供访问
  2. 通过 operator[]
  3. 提供对数据成员的直接访问
  4. 不会破坏默认数据成员对齐(std::array 是线性的,它会破坏您的 class 数据成员的编译器优化对齐)

以下代码满足上述要求,没有任何非标准特性:

template<typename T, size_t S>
struct Vec;
template<typename T>
struct Vec<T, 1> {
  enum {count = 1};
  T x;
  T& operator[](size_t i) {
    assert(i == 0);
    return x;
  }
  const T& operator[](size_t i) const {
    assert(i == 0);
    return x;
  }
};
template<typename T>
struct Vec<T, 2> {
  enum { count = 2 };
  T x;
  T y;
  T& operator[](size_t i) {
    assert(0 <= i && i < count);
    return this->*(pointer(i));
  }
  const T& operator[](size_t i) const {
    assert(0 <= i && i < count);
    return this->*(pointer(i));
  }
  static T Vec::* pointer(size_t i) {
    static T Vec::* a[count] = { &Vec::x, &Vec::y };
    return a[i];
  }
};
template<typename T>
struct Vec<T, 3> {
  enum { count = 3 };
  T x;
  T y;
  T z;
  T& operator[](size_t i) {
    assert(0 <= i && i < count);
    return this->*(pointer(i));
  }
  const T& operator[](size_t i) const {
    assert(0 <= i && i < count);
    return this->*(pointer(i));
  }
  static T Vec::* pointer(size_t i) {
    static T Vec::* a[count] = { &Vec::x, &Vec::y, &Vec::z };
    return a[i];
  }
};

int main() {
  Vec<int, 2> v1{ 1, 2 };
  assert(v1[0] == v1.x);
  assert(v1[1] == v1.y);

  Vec<unsigned char, 3> v2{ 4, 5, 6 };
  assert(v2[0] == v2.x);
  assert(v2[1] == v2.y);
  assert(v2[2] == v2.z);
  return 0;
}