我正在创建一个向量类,而不是为Vector2
,Vector3
和Vector4
创建单独的类,而是想做一个多合一的类。我的问题是,我想根据向量的大小来定义某些属性。例如,大小2
的向量将具有x
和y
组件,而不是z
组件。
我正在尝试使用#if
指令来检查非类型模板参数(SIZE
(以根据向量的大小创建属性。我做了一些研究,我认为这是不可能的。我想知道是否有人想知道如何实现我想要的?
template <typename T, int SIZE>
class Vector
{
public:
union
{
struct
{
#if SIZE == 2
T x, y;
#endif
#if SIZE == 3
T z;
#endif
#if SIZE == 4
T w;
#endif
};
T data[SIZE];
};
};
我希望能够创建和访问这样的向量:
Vector<int, 2> vec2;
vec2.x;
Vector<int, 3> vec3;
vec3.z;
任何反馈都将不胜感激!
编辑:在回顾了评论后,我提出了一个漂亮的解决方案……希望它对我有用。我创建了一个模板类:
template <typename T, unsigned int SIZE> class _vec;
这涉及向量的数据(组件(并包含行为。然后,我做了另一个模板类,它将像这样专业化_vec
:
template <typename T, unsigned int SIZE> class Vector : public _vec<T, SIZE>;
这是任何大小的向量。现在,我可以将其专门用于Vector2
,Vector3
和Vector4
:
template <typename T> class Vector<T, 2> : public _vec<T, 2>;
template <typename T>
using Vector2 = Vector<T, 2>;
我会让你知道这将有多可怕...; p
编辑2:它有效,但没有奏效... :(
不,这是不可能的。
在翻译的阶段,预处理阶段是在模板实例化阶段之前的。因此,在这种情况下,您最终将没有template Vector
中定义的变量,因为在预处理阶段未定义SIZE
。
根据C 标准, [cpp.cond]/9
:
由于宏观扩展和评估定义的 - 麦克罗表达和 has-include-expressions
,所有其余的标识符和关键词都进行了
true
和false
,被替换为 pp-number0
,然后将每个预处理令牌转换为令牌。
因此,SIZE
的值将为0
,因此没有满足条件包含的条件。
您可以将模板专门用于具有不同实例的不同变量。
免责声明:我从这个代码库中得到了这个想法。似乎有一些用户也在评论中指出了这一点。
否。预处理指令是不可能的,但是您可以使用模板专业化:
template <typename T, unsigned int S>
struct vec {
T data[S];
};
template <typename T>
struct vec<T, 2> {
T x, y;
};
template <typename T>
struct vec<T, 3> {
T x, y, z;
};
template <typename T>
struct vec<T, 4> {
T x, y, z, w;
};
如果您真的愿意,则可以将联盟添加回中,但这是不确定的行为。相反,您可以制作X,Y和Z功能,并让它们返回参考数组:
template <typename T, unsigned int S>
struct vec {
T data[S];
};
template <typename T>
struct vec<T, 2> {
T data[2];
T& x() { return data[0]; }
const T& x() const { return data[0]; }
T& y() { return data[1]; }
const T& y() const { return data[1]; }
};
template <typename T>
struct vec<T, 3> {
T data[3];
T& x() { return data[0]; }
const T& x() const { return data[0]; }
T& y() { return data[1]; }
const T& y() const { return data[1]; }
T& z() { return data[2]; }
const T& z() const { return data[2]; }
};
template <typename T>
struct vec<T, 4> {
T data[4];
T& x() { return data[0]; }
const T& x() const { return data[0]; }
T& y() { return data[1]; }
const T& y() const { return data[1]; }
T& z() { return data[2]; }
const T& z() const { return data[2]; }
T& w() { return data[3]; }
const T& w() const { return data[3]; }
};
如果您有所有课程中都应该可用的东西,则可以介绍另一个类,例如 vec_
可以做到并从中继承(在那里添加数据数组,并且具有标量产品仅访问数组(。
如果您使用的是C 17,我建议将[[nodiscard]] constexpr
添加到X,Y和Z函数中,但这只会在示例中混乱。
如评论中所述,该设计也许不是最好的,并且不能与宏作用。
但是,如果您想尝试一下,就可以使用array<T, size> data
简化作业并为自然名称创建功能:
inline T x() const { return data[0]; }
等等。现在事情变得非常棘手,因为例如,z()
功能仅适用于3和4的向量。使用模板Black Magic和Sfinae应该使其成为可能,但是我不知道是否值得。有关完整的说明,请参见Vittorio Romeo网站。