3d矢量算术模板(如何专门为int和浮动版本)

时间:2015-01-19 15:26:33

标签: c++ templates

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

4 个答案:

答案 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;