假设我们有具有不同成员类型和数量的不同类(结构)。为了便于说明,它们是2D和3D向量。
struct i2 {
int a, b;
i(int a, int b): a(a), b(b) {}
};
struct f2 {
float a, b;
f(float a, float b): a(a), b(b) {}
};
struct i3 {
int a, b, c;
i(int a, int b): a(a), b(b), c(c) {}
};
struct f3 {
float a, b, c;
f(float a, float b): a(a), b(b), c(c) {}
};
我想以模板方式实现一些相关功能。在课外说一个加法运算符,例如
template<class Type> Type operator+(const Type& P, const& Type Q)
{ return Type(P.a + Q.b, P.a + P.b); }
很明显,这不适用于3D变体,这需要
template<class Type> Type operator+(const Type& P, const Type& Q)
{ return Type(P.a + Q.a, P.b + P.b, P.c + Q.c); }
在没有众多显式专业的情况下,是否有一种很好的方法来实现这一目标?如果它使用高级C ++功能,将支持该功能的最低版本是什么?
换句话说,是否存在一种编译时机制来根据参数类型有条件地实例化模板?
请注意,我希望初始类保持非模板状态,因为这会在设计中引入其他问题。
答案 0 :(得分:1)
一旦拥有特质,就可以使用SFINAE。
特征可以在任何版本的C ++中完成,即使使用更新的版本会更容易。
根据您要如何定义特征,可以使用类似的
template <typename T>
using is_2d_vector = std::disjunction_t<std::is_same<T, i2>, std::is_same<T, f2>>;
template <typename T>
using is_3d_vector = std::disjunction_t<std::is_same<T, i3>, std::is_same<T, f3>>;
// possible alternatives include detection of T::a, T::b, T::c
template<class T, std::enable_if_t<is_2d_vector<T>, int> = 0>
T operator+(const T& lhs, const T& rhs)
{ return T(lhs.a + rhs.a, lhs.b + rhs.b); }
template<class T, std::enable_if_t<is_3d_vector<T>, int> = 0>
T operator+(const T& lhs, const T& rhs)
{ return T(lhs.a + rhs.a, lhs.b + rhs.b, lhs.c + rhs.c); }
但是最初拥有模板类似乎更简单:
template <typename T>
struct T2 {
T a, b;
T2(T a, T b): a(a), b(b) {}
friend operator +(const T2& lhs, const T2& rhs)
{ return T(lhs.a + rhs.a, lhs.b + rhs.b); }
};
template <typename T>
struct T3 {
T a, b, c;
T3(T a, T b, T c): a(a), b(b), c(c) {}
friend operator +(const T2& lhs, const T2& rhs)
{ return T(lhs.a + rhs.a, lhs.b + rhs.b, lhs.c + rhs.c); }
};
using i2 = T2<int>;
using i3 = T3<int>;
using f2 = T2<float>;
using f3 = T3<float>;
答案 1 :(得分:0)
我认为做到这一点的一种方法是使用编译时(静态)反射。在线上有很多文章,其中有两篇,https://medium.com/@vesko.karaganev/compile-time-reflection-in-c-17-55c14ee8106b 和 https://Frly.sexy/post/basic-reflection-in-pure-cpp17
但是我不确定这是解决问题的最佳方法,因为更好的答案将需要更多具体细节。