3

我有以下内容:

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

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

我基本上想添加一个方法 toPoint(),如果 T=float 则返回 struct 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<float>,因为它实际上是基类。我可以为 normalize() 和基类中的任何其他公共方法添加包装器方法,但我不想这样做,因为它会使维护这些类变得乏味。

我还尝试将 typedef 放回并在模板定义之外添加:

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

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

这不会编译,因为 toPoint() 没有在模板定义中声明。由于返回类型 Point3f/Point3d,我无法将其放入其中。

我该怎么做呢?任何帮助是极大的赞赏!

4

4 回答 4

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;
};
于 2013-07-12T13:41:49.350 回答
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;
于 2013-07-12T13:44:36.320 回答
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 的自然挂件,我更喜欢第二个模板参数。

于 2013-07-12T13:56:17.173 回答
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();
}
于 2013-07-12T16:34:01.607 回答