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
- 通过 .x、.y 等数据成员选择器提供访问
- 通过 operator[]
提供对数据成员的直接访问
- 不会破坏默认数据成员对齐(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;
}
我有以下向量 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
- 通过 .x、.y 等数据成员选择器提供访问
- 通过 operator[] 提供对数据成员的直接访问
- 不会破坏默认数据成员对齐(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;
}