3d矢量算术模板(如何专门用于int和float版本)

Template for 3d vector arithmetics (how to specialize for int and float version )

本文关键字:int 用于 何专门 float 版本 3d      更新时间:2023-10-16

我想做一个通用的通用模板,它指定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;