我想制作一个通用的通用模板,它指定3D矢量上的所有3D数学,而不是专门用于浮点(双精度)(称为Vec3d)和整数(称为Vec3i)。我希望在没有重新实现公共代码的情况下执行此操作。
有人建议通过继承而不是专业来做。但是当我这样做时,我得到了这个错误:
main.cpp:34:12: error: could not convert ‘dR.Vec3d::<anonymous>.Vec3TYPE<TYPE>::operator*<double>(k)’ from ‘Vec3TYPE<double>’ to ‘Vec3d’
返回dR * k; //有错误
代码是这样的(提取相关部分):
#include <math.h>
#include <cstdio>
// definition of general template
template <class TYPE>
class Vec3TYPE{
public:
union{
struct{ TYPE x,y,z; };
struct{ TYPE a,b,c; };
TYPE array[3];
};
inline void set( TYPE f ) { x=f; y=f; z=f; };
inline void set( TYPE fx, TYPE fy, TYPE fz ) { x=fx; y=fy; z=fz; };
inline void set( const Vec3TYPE& v ) { x=v.x; y=v.y; z=v.z; };
inline Vec3TYPE operator+ ( TYPE f ) const { Vec3TYPE vo; vo.x=x+f; vo.y=y+f; vo.z=z+f; return vo; };
inline Vec3TYPE operator* ( TYPE f ) const { Vec3TYPE vo; vo.x=x*f; vo.y=y*f; vo.z=z*f; return vo; };
inline Vec3TYPE operator+ ( const Vec3TYPE& vi ) const { Vec3TYPE vo; vo.x=x+vi.x; vo.y=y+vi.y; vo.z=z+vi.z; return vo; };
inline Vec3TYPE operator- ( const Vec3TYPE& vi ) const { Vec3TYPE vo; vo.x=x-vi.x; vo.y=y-vi.y; vo.z=z-vi.z; return vo; };
inline Vec3TYPE operator* ( const Vec3TYPE& vi ) const { Vec3TYPE vo; vo.x=x*vi.x; vo.y=y*vi.y; vo.z=z*vi.z; return vo; };
inline Vec3TYPE operator/ ( const Vec3TYPE& vi ) const { Vec3TYPE vo; vo.x=x/vi.x; vo.y=y/vi.y; vo.z=z/vi.z; return vo; };
};
// specialization
class Vec3i : public Vec3TYPE<int>{}; // int version
class Vec3d : public Vec3TYPE<double>{ // float version
public:
inline double norm ( ) const { return sqrt( x*x + y*y + z*z ); };
};
inline Vec3d getForce( Vec3d dR, double k ){
return dR * k; // there is the error
}
// main
int main(){
Vec3d a; a.set( 1.0, 2.0, 3.0 );
// this works
Vec3d b; b.set( a * 4.0 );
printf( " %f %f %f \n", b.x, b.y, b.z );
// this does not
Vec3d b_; b_.set( getForce( a, 4.0 ) );
printf( " %f %f %f \n", b.x, b.y, b.z );
}
答案 0 :(得分:1)
使用我在评论中提到的Curiously recurring template pattern,你可能会做类似的事情。
template <typename TYPE, typename CHILD>
class Vec3TYPE{
public:
union{
struct{ TYPE x,y,z; };
struct{ TYPE a,b,c; };
TYPE array[3];
};
inline CHILD operator+ ( TYPE f ) const { CHILD vo; vo.x=x+f; vo.y=y+f; vo.z=z+f; return vo; };
// etc.
};
// specialization
class Vec3i : public Vec3TYPE<int, Vec3i>{}; // int version
class Vec3d : public Vec3TYPE<double, Vec3d>{ // float version
public:
inline double norm ( ) const { return sqrt( x*x + y*y + z*z ); };
};
答案 1 :(得分:0)
问题是Vec3TYPE<TYPE>::operator*
返回Vec3TYPE<TYPE>
类型的对象。另一方面,getForce
必须返回Vec3d
。设计的一个简单的解决方法是通过添加以下构造函数使Vec3d
可以从Vec3TYPE<double>
构造,该构造函数从参数构造基础对象。
Vec3d(const Vec3TYPE<double>& parent): Vec3TYPE<double>(parent){}
但是,我并不相信继承会增加任何有用的东西。我建议您考虑使用Vec3TYPE
而不使用衍生物的设计。计算norm
对于整数向量也很有用。显然,将范数作为整数返回通常不是您通常想要的。您可以通过将其设为模板来解决此问题:
template<class Rtype = TYPE> // the default param requires c++11
inline RType norm ( ) const { return sqrt( x*x + y*y + z*z ); };
答案 2 :(得分:0)
错误消息很糟糕,但原因是没有从Vec3TYPE<double>
转换为Vec3d
。
(dR.Vec3d::<anonymous>.Vec3TYPE<TYPE>::operator*<double>(k)
指的是操作dR * k
的结果,这不是世界上最明显的事情。)
没有转换的原因是没有从基类到子类的默认转换。
需要转换的原因是operator*
返回Vec3TYPE<double>
,而不是Vec3d
。
如果你真的想要使用继承,你需要提供一个Vec3TYPE<double>
Vec3d
的构造函数。
答案 3 :(得分:0)
正如其他答案中所解释的那样,问题是由于没有充分理由使用继承引起的。只是不要在这里使用继承。而且,对于一般功能,我将使用非成员函数,例如(在与Vec3TYPE<>
相同的命名空间中声明)
inline double norm(Vec3TYPE<double> const&v) noexcept
{
return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
}
不过,为什么Vec3TYPE<int>
也没有规范(返回int
)?
没有继承,您只需定义
typedef Vec3TYPE<double> Vec3d;
typedef Vec3TYPE<int> Vec3i;