3d 矢量算术模板(如何专门针对 int 和 float 版本)
Template for 3d vector arithmetics (how to specialize for int and float version )
我想制作一个通用的通用模板,它指定 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’
return 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 );
}
问题是 Vec3TYPE<TYPE>::operator*
return 是一个 Vec3TYPE<TYPE>
类型的对象。 getForce
另一方面必须 return 一个 Vec3d
。您的设计的一个简单解决方法是通过添加以下构造函数来使 Vec3d
可从 Vec3TYPE<double>
构造,该构造函数从参数复制构造基础对象。
Vec3d(const Vec3TYPE<double>& parent): Vec3TYPE<double>(parent){}
但是,我不相信继承会增加任何有用的东西。我建议您考虑使用 Vec3TYPE
而不使用导数的设计。计算 norm
对整数向量也很有用。显然,return 将范数作为整数通常不是您通常想要的。您可以通过将其设为模板来解决此问题:
template<class Rtype = TYPE> // the default param requires c++11
inline RType norm ( ) const { return sqrt( x*x + y*y + z*z ); };
错误消息很可怕,但原因是没有从 Vec3TYPE<double>
到 Vec3d
的转换。
(dR.Vec3d::<anonymous>.Vec3TYPE<TYPE>::operator*<double>(k)
指的是dR * k
运算的结果,这不是世界上最明显的东西。)
没有转换的原因是没有从base class到subclass的默认转换。
需要转换的原因是 operator*
returns 一个 Vec3TYPE<double>
,而不是一个 Vec3d
.
如果你真的想使用继承,你需要提供一个在Vec3d
.
中接受Vec3TYPE<double>
的构造函数
正如其他答案中所解释的那样,问题是由没有充分理由使用继承引起的。只是不要在这里使用继承。此外,对于一般功能,我会使用非成员函数,例如(在与 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;
使用我在评论中提到的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 ); };
};
我想制作一个通用的通用模板,它指定 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’
return 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 );
}
问题是 Vec3TYPE<TYPE>::operator*
return 是一个 Vec3TYPE<TYPE>
类型的对象。 getForce
另一方面必须 return 一个 Vec3d
。您的设计的一个简单解决方法是通过添加以下构造函数来使 Vec3d
可从 Vec3TYPE<double>
构造,该构造函数从参数复制构造基础对象。
Vec3d(const Vec3TYPE<double>& parent): Vec3TYPE<double>(parent){}
但是,我不相信继承会增加任何有用的东西。我建议您考虑使用 Vec3TYPE
而不使用导数的设计。计算 norm
对整数向量也很有用。显然,return 将范数作为整数通常不是您通常想要的。您可以通过将其设为模板来解决此问题:
template<class Rtype = TYPE> // the default param requires c++11
inline RType norm ( ) const { return sqrt( x*x + y*y + z*z ); };
错误消息很可怕,但原因是没有从 Vec3TYPE<double>
到 Vec3d
的转换。
(dR.Vec3d::<anonymous>.Vec3TYPE<TYPE>::operator*<double>(k)
指的是dR * k
运算的结果,这不是世界上最明显的东西。)
没有转换的原因是没有从base class到subclass的默认转换。
需要转换的原因是 operator*
returns 一个 Vec3TYPE<double>
,而不是一个 Vec3d
.
如果你真的想使用继承,你需要提供一个在Vec3d
.
Vec3TYPE<double>
的构造函数
正如其他答案中所解释的那样,问题是由没有充分理由使用继承引起的。只是不要在这里使用继承。此外,对于一般功能,我会使用非成员函数,例如(在与 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;
使用我在评论中提到的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 ); };
};