C ++:扩展模板类

时间:2013-07-12 13:31:33

标签: c++ templates specialization

我有以下内容:

template<typename T> class CVector3
{
    CVector3<T> &normalize();
    // more stuff
};

typedef CVector3<float> Vector3f;
typedef CVector3<double> Vector3d;

我基本上想要添加一个方法toPoint(),如果T = float则返回结构Point3f,如果T = double则返回struct Point3d。我尝试用以下代码替换两个typedef:

class Vector3f: public CVector3<float>
{
    Point3f toPoint() const;
};

class Vector3d: public CVector3<double>
{
    Point3d toPoint() const;
};

然而,这不起作用,因为现在normalize()被破坏了:它不再返回Vector3f,而是返回与Vector3f不兼容的CVector3&lt; float&gt;,因为它实际上是基类。我可以为基类中的normalize()和任何其他公共方法添加包装器方法,但我不想这样做,因为它会使维护这些类变得乏味。

我还尝试重新输入typedef并在模板定义之外添加:

template<>
Point3f CVector3<float>::toPoint() const;

template<>
Point3d CVector3<double>::toPoint() const;

这不会编译,因为toPoint()未在模板定义中声明。我不能把它放在里面,因为返回类型为Point3f / Point3d。

我该怎么做?非常感谢任何帮助!

4 个答案:

答案 0 :(得分:3)

您可以使用特征风格助手类。

template<typename T> CVectorTraits {};
template<> CVectorTraits<double> { typedef Point3d PointType; }
template<> CVectorTraits<float> { typedef Point3f PointType; }

template<typename T> class CVector3
{
    CVector3<T> &normalize();
    // more stuff
    typename CVectorTraits<T>::PointType toPoint() const;
};

答案 1 :(得分:1)

您可以使用类型特征:

template<typename T>
struct VectorTraits;

template<>
struct VectorTraits<float> {
     typedef Point3f Point;
};
template<>
struct VectorTraits<double> {
     typedef Point3d Point;
};

template<typename T> class CVector3
{
    CVector3<T> &normalize();

    typename VectorTraits<T>::Point 
    toPoint() const;

    // more stuff
};

typedef CVector3<float> Vector3f;
typedef CVector3<double> Vector3d;

答案 2 :(得分:0)

感谢您的回复,我现在想出了一种应该有效的方法:

template<typename T, typename P> class CVector3
{
    CVector3<T, P> &normalize();
    // more stuff

    P toPoint() const;
};

typedef CVector3<float, Point3f> Vector3f;
typedef CVector3<double, Point3d> Vector3d;

我打算尝试一下,然后告诉你它是否有效。干杯!

编辑:是的,它有效!我不得不像这样定义toPoint():

template<>
Point3f CVector3<float, Point3f>::toPoint() const
{
    Point3f pt = { x, y, z };
    return pt;
}

你的特征答案肯定是一个更通用的解决方案,但由于Point3f是Vector3f的天然吊坠,我更喜欢第二个模板参数。

答案 3 :(得分:0)

您可以改进客户端的语法,并强制执行约束以确保客户端不会通过使用专门化来解决模板参数错误。

struct Point3f { float x, y, z; };
struct Point3d { double x, y, z; };

// Base template toPoint returns Point3f.
template<typename T, typename U = Point3f>
class Vector3
{
public:
   Vector3& normalize(){ return Vector3(); }
   U toPoint(){ return Point3f(); }
};

// Specialization for double, toPoint returns Point3d.
template<>
class Vector3<double>
{
public:
   Vector3& normalize(){ return Vector3(); }
   Point3d toPoint(){ return Point3d(); }
};


TEST(TemplateTests2, Test3)
{
   Vector3<float> v1;
   Point3f p1 = v1.toPoint();

   Vector3<double> v2;
   Point3d p2 = v2.toPoint();
}