具有共享功能的类模板特化 [英] Class template specializations with shared functionality

查看:113
本文介绍了具有共享功能的类模板特化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用模板向量类型写一个简单的数学库:

  template< typename T,size_t N& 
class Vector {
public:
Vector< T,N> & operator + =(Vector< T,N> const& other);
// ...更多运算符,函数...
};

现在我想要一些额外功能。假设我想要在上的函数 x() y() ; 来访问特定的坐标。我可以为此创建一个部分专门化:

  template< typename T& 
class Vector< T,3> {
public:
Vector< T,3> & operator + =(Vector< T,3> const& other);
// ...再次所有的运算符和函数...
T x()const;
T y()const;
};

但现在我重复一般模板中已经存在的一切。



我也可以使用继承。将通用模板重命名为 VectorBase ,我可以这样做:

  template< ;类型名称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;
};然而,现在的问题是所有的操作符都定义在 VectorBase code>,因此它们返回 VectorBase 实例。这些不能分配给向量变量:

 向量< float,3& ; v; 
Vector< float,3> w;
w = 5 * v; //错误:没有从VectorBase转换< float,3>到Vector< float,3>

我可以给 Vector 一个隐式转换构造函数这使得可能:

 模板< typename T,size_t N& 
class Vector:public VectorBase< T,N> {
public:
Vector(VectorBase< T,N> const& other);
};

但是,现在我正在从 Vector VectorBase ,然后再返回。即使类型在内存中是相同的,编译器可能会优化所有这些,它感觉笨重,我真的不想有潜在的运行时间开销本质上是一个编译时问题。



有没有其他方法来解决这个问题?

解决方案

CRTP 来解决此问题。此成语用于 boost :: operator

 模板< typename ChildT,typename T,int N> 
class VectorBase
{
public:
/ *如果必要的话,使用static_cast我们知道'ChildT'是一个'VectorBase'* /
朋友ChildT运算符* 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(); //错误!
}


I'm writing a simple maths library with a template vector type:

template<typename T, size_t N>
class Vector {
    public:
        Vector<T, N> &operator+=(Vector<T, N> const &other);
        // ... more operators, functions ...
};

Now I want some additional functionality specifically for some of these. Let's say I want functions x() and y() on Vector<T, 2> to access particular coordinates. I could create a partial specialization for this:

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;
};

But now I'm repeating everything that already existed in the generic template.

I could also use inheritance. Renaming the generic template to VectorBase, I could do this:

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;
};

However, now the problem is that all operators are defined on VectorBase, so they return VectorBase instances. These cannot be assigned to Vector variables:

Vector<float, 3> v;
Vector<float, 3> w;
w = 5 * v; // error: no conversion from VectorBase<float, 3> to Vector<float, 3>

I could give Vector an implicit conversion constructor to make this possible:

template<typename T, size_t N>
class Vector : public VectorBase<T, N> {
    public:
        Vector(VectorBase<T, N> const &other);
};

However, now I'm converting from Vector to VectorBase and back again. Even though the types are the same in memory, and the compiler might optimize all this away, it feels clunky and I don't really like to have potential run-time overhead for what is essentially a compile-time problem.

Is there any other way to solve this?

解决方案

I think you can use CRTP to solve this problem. This idiom is used in 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 !!
}

这篇关于具有共享功能的类模板特化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆