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’
返回 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 );
}
使用我在评论中提到的奇怪重复出现的模板模式,您也许可以做类似的事情。
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 ); };
};
错误消息很可怕,但原因是没有从Vec3TYPE<double>
到Vec3d
的转换。
(dR.Vec3d::<anonymous>.Vec3TYPE<TYPE>::operator*<double>(k)
指的是dR * k
操作的结果,这不是世界上最明显的事情。
没有转换的原因是没有从基类到子类的默认转换。
需要转换的原因是operator*
返回Vec3TYPE<double>
,而不是Vec3d
。
如果你真的想使用继承,你需要提供一个在Vec3d
中接受Vec3TYPE<double>
的构造函数。
问题是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 ); };
正如其他答案中所解释的,这个问题是由没有充分理由使用继承引起的。只是不要在这里使用继承。此外,对于一般功能,我会使用非成员函数,例如(在与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;
- 运算符 += 应用于 std::valarray<int*>
- C ++ txt 文件成数组逐行字符串和 int 用于纸牌游戏
- 使输出流式处理运算符适用于 boost::variant<std::vector<int>、int、double 的正确方法是什么>
- 为什么基于 int 的访问不适用于 std::get(std::tuple)?
- 正确语法,用于统一初始化名称中带有空格的类型的临时,如unsigned int
- 如何证明 -> 在 int* pMember = &(pSomeType->SomeIntMember) 时不用于顺从;
- 用于检查"is int"/"is double"/等的模板函数
- sqlite3 更改函数回调参数 void* not用于 int* C++
- 为什么现代C 仍然保留旧的C样式原型,用于int argc,char ** argv
- 是否有任何用于ConstexPR操作员 (INT)的应用程序(INT)
- 双指针 (int**) 和双括号,用于从 2D 数组中获取值
- OpenCL 的 clEnqueueReadBufferRect 适用于 int 但不适用于 double 数据类型
- 使用4用于循环的4矩阵上的数组下标的“ int [int]类型”
- 检测输入键的输入键,用于INT类型
- 无法获得 boost::spirit parser&lexer 适用于 std::string 或 int 或 double 以外的令牌类型
- map(long long int,long long int)不适用于key=1000 000 000(在long l
- Qt警告:正在传递用于转换QRect的qreal::QRect(int,int,int)
- 重载分辨率如何适用于 std::vector:<int>:insert
- C 不是运算符应用于 int
- 无法将向量<int>转换为 int* 用于布尔测试密码