代码之家  ›  专栏  ›  技术社区  ›  DaClown

用作比较双精度值的模板参数的类型

  •  1
  • DaClown  · 技术社区  · 16 年前

    我得到了这个n维的点对象:

    template <class T, unsigned int dimension> class Obj {
    protected:
        T coords[dimension];
        static const unsigned int size = dimension;
    public:
        Obj() { };
        Obj(T def) { for (unsigned int i = 0; i < size; ++i) coords[i]=def; };
        Obj(const Obj& o) { for (unsigned int i = 0; i < size; ++i) coords[i] = o.coords[i]; }
        const Obj& operator= (const Obj& rhs) { if (this != &rhs) for (unsigned int i = 0; i < size; ++i) coords[i] = rhs.coords[i]; return *this; }
    
    
        virtual ~Obj() {  };
        T get (unsigned int id) { if (id >= size) throw std::out_of_range("out of range"); return coords[id]; }
        void set (unsigned int id, T t) { if (id >= size) throw std::out_of_range("out of range"); coords[id] = t; }
    
    };
    

    以及使用obj作为基本类的3D点类:

    template <class U> class Point3DBase : public Obj<U,3> {
        typedef U type;
    
    public:
        U &x, &y, &z;
    public:
        Point3DBase() : x(Obj<U,3>::coords[0]), y(Obj<U,3>::coords[1]), z(Obj<U,3>::coords[2]) { };
        Point3DBase(U def) : Obj<U,3>(def), x(Obj<U,3>::coords[0]), y(Obj<U,3>::coords[1]), z(Obj<U,3>::coords[2]) { };
        Point3DBase(U x_, U y_, U z_) : x(Obj<U,3>::coords[0]), y(Obj<U,3>::coords[1]), z(Obj<U,3>::coords[2])  { x = x_; y = y_; z= z_; };
        Point3DBase(const Point3DBase& other) : x(Obj<U,3>::coords[0]), y(Obj<U,3>::coords[1]), z(Obj<U,3>::coords[2]) { x = other.x; y = other.y; z = other.z; }
    // several operators ...
    };
    

    运算符,基本上是用于比较的运算符,使用简单的比较成员对象方法,如:

    friend bool operator== (const Point3DBase<U> &lhs, const Point3DBase<U> rhs) { return (lhs.x ==  rhs.x && lhs.y == rhs.y && lhs.z == rhs.z); }
    

    然后我发现,对于双值的比较,简单的相等方法不是很有用,因为双值应该与误差幅度进行比较。在这一点上引入误差幅度的最佳方法是什么?我考虑了一个epspdouble类型作为模板参数,但我不知道如何实现这一点。

    编辑:

    我见过链接的输出流操作符,它们调用输出流操作符类型的输出流操作符…是否有方法将比较委托给表示浮点类型的自定义类型?

    3 回复  |  直到 16 年前
        1
  •  3
  •   Matthieu M.    16 年前

    如果要为给定浮点类型的所有实例使用一个epsilon值,实际上非常简单:

    template <>
    bool operator<(const Point3DBase<double>& lhs, const Point3DBase<double>& rhs)
    {
    }
    

    如果没有,那我就把你引向 基于策略的设计 如亚历山德里斯科所示:

    namespace detail
    {
      template <class U>
      struct DefaultComparator: std::binary_function<bool, U, U>
      {
        bool operator()(U lhs, U rhs) const { return lhs < rhs; }
      };
    }
    
    template < class U, class Comparator = detail::DefaultComparator<U> >
    class Point3DBase;
    
    template < class U, class C>
    bool operator<(Point3DBase<U,C> const& lhs, Point3DBase<U,C> const& rhs)
    {
      return C()(lhs,rhs);
    }
    

    注意,您仍然可以通过专门化定义安全默认值 DefaultComparator

    namespace detail
    {
      template <>
      struct DefaultComparator<float> {};
    
      template <>
      struct DefaultComparator<double> {};
    }
    

    有了这个定义,就不可能使用 operator== 不通过 Comparator 参数本身。另一个解决方案是允许它,但在上面两个专门化的定义中提供一个默认的epsilon。

    所有其他操作( >, <=, >=, ==, != )可以从 < 例如,从 boost::equality_comparable 和/或 boost::less_than_comparable .

        2
  •  1
  •   Péter Török    16 年前

    是的,不能有浮点类型的模板参数。您可以使用一个int参数,告诉epsilon值的负10基对数,例如,值为3表示0.001。

        3
  •  1
  •   Vicente Botet Escriba    16 年前

    如果您想掌握epsilon,您可以定义一个double包装类,在比较这个epsilon类的实例时,它负责处理这个epsilon。通过这种方式,您可以使用在数值类型上模板化的任何其他函数或类。

    template <int EPS>
    class DoubleEps {
      double val;
    public:
      operator double {return val;}
      DoubleEps(double d) : val(d) {}
      operator==(DoubleEps d) {
        // take care of epsilon 
      }
      // other operators if needed
    };