是否可以使用模板非类型参数使用#if指令?(矢量多合一类)



我正在创建一个向量类,而不是为Vector2Vector3Vector4创建单独的类,而是想做一个多合一的类。我的问题是,我想根据向量的大小来定义某些属性。例如,大小2的向量将具有xy组件,而不是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>;

这是任何大小的向量。现在,我可以将其专门用于Vector2Vector3Vector4

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

,所有其余的标识符和关键词都进行了truefalse被替换为 pp-number 0 ,然后将每个预处理令牌转换为令牌。

因此,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网站。

最新更新