C++:扩展一个模板类

C++: Extending a template class

本文关键字:一个 扩展 C++      更新时间:2023-10-16

我得到了以下内容:

template<typename T> class CVector3
{
    CVector3<T> &normalize();
    // more stuff
};
typedef CVector3<float> Vector3f;
typedef CVector3<double> Vector3d;

我基本上想添加一个方法,toPoint(),如果T=float,它会返回一个结构体Point3f,如果T=double,它会输出一个结构物Point3d。我试着用替换这两个typedef

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

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

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

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

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

我该怎么做?非常感谢您的帮助!

您可以使用traits样式的辅助类。

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

您可以使用类型特征:

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;

感谢您的回复,我现在已经找到了一种可行的方法:

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的自然吊坠,我更喜欢第二个模板参数。

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

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();
}
相关文章: