Tho*_*mas 15 c++ templates template-specialization
我正在编写一个带有模板矢量类型的简单数学库:
template<typename T, size_t N>
class Vector {
public:
Vector<T, N> &operator+=(Vector<T, N> const &other);
// ... more operators, functions ...
};
Run Code Online (Sandbox Code Playgroud)
现在我想要一些专门用于其中一些功能的附加功能.比方说,我想要的功能x(),并y()在Vector<T, 2>访问特定的坐标.我可以为此创建一个部分特化:
template<typename T>
class Vector<T, 3> {
public:
Vector<T, 3> &operator+=(Vector<T, 3> const &other);
// ... and again all the operators and functions ...
T x() const;
T y() const;
};
Run Code Online (Sandbox Code Playgroud)
但现在我正在重复通用模板中已存在的所有内容.
我也可以使用继承.将通用模板重命名为VectorBase,我可以这样做:
template<typename T, size_t N>
class Vector : public VectorBase<T, N> {
};
template<typename T>
class Vector<T, 3> : public VectorBase<T, 3> {
public:
T x() const;
T y() const;
};
Run Code Online (Sandbox Code Playgroud)
但是,现在的问题是所有运算符都已定义VectorBase,因此它们返回VectorBase实例.这些不能分配给Vector变量:
Vector<float, 3> v;
Vector<float, 3> w;
w = 5 * v; // error: no conversion from VectorBase<float, 3> to Vector<float, 3>
Run Code Online (Sandbox Code Playgroud)
我可以给出Vector一个隐式转换构造函数来实现这个:
template<typename T, size_t N>
class Vector : public VectorBase<T, N> {
public:
Vector(VectorBase<T, N> const &other);
};
Run Code Online (Sandbox Code Playgroud)
不过,现在我从转换Vector到VectorBase,然后再返回.尽管类型在内存中是相同的,并且编译器可能会优化所有这些,但它感觉很笨,我真的不喜欢潜在的运行时开销,这本质上是一个编译时问题.
有没有其他方法可以解决这个问题?
我认为你可以使用CRTP来解决这个问题.这个习惯用法在boost :: operator中使用.
template<typename ChildT, typename T, int N>
class VectorBase
{
public:
/* use static_cast if necessary as we know that 'ChildT' is a 'VectorBase' */
friend ChildT operator*(double lhs, ChildT const &rhs) { /* */ }
friend ChildT operator*(ChildT const &lhs, double rhs) { /* */ }
};
template<typename T, size_t N>
class Vector : public VectorBase<Vector<T,N>, T, N>
{
};
template<typename T>
class Vector<T, 3> : public VectorBase<Vector<T, 3>, T, 3>
{
public:
T x() const {}
T y() const {}
};
void test()
{
Vector<float, 3> v;
Vector<float, 3> w;
w = 5 * v;
w = v * 5;
v.x();
Vector<float, 5> y;
Vector<float, 5> z;
y = 5 * z;
y = z * 5;
//z.x(); // Error !!
}
Run Code Online (Sandbox Code Playgroud)