tags:

views:

77

answers:

3

I got this n-dimensional point object:

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; }

};

and a 3D point class which uses Obj as base class:

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 ...
};

The operators, basically the ones for comparison, use the simple compare-the-member-object approach like:

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

Then it occured to me that for the comparion of double values the simply equality approach is not very useful since double values should be compared with an error margin. What would be the best approach to introduce an error margin into the point? I thought about an epsDouble type as template parameter but I can't figure out how to achieve this.

edit:

I've seen chained output stream operators that call the output stream operator of the type of the output stream operator ... Is there a way to delegate the comparison to a custom type that represents a float point type?

+1  A: 

Yeah, you can't have a template parameter of a floating point type. You could have an int parameter instead, telling the negative 10 base log of the epsilon value, e.g. a value of 3 would mean 0.001 .

Péter Török
+1  A: 

If you want to master the epsilon you can define a wrapper class of double that takes care of the this epsilon when comparing instances of this class. In this way you are able to use whatever other functions or classes that are templated on the numeric type.

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
};
Vicente Botet Escriba
+3  A: 

If you want one epsilon value for all instances of a given floating type, it's actually quite simple:

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

If not, then I shall orient you toward Policy-based Design as Alexandrescu showed:

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);
}

Note that you can still define a safe default by specializing DefaultComparator

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

  template <>
  struct DefaultComparator<double> {};
}

With this definition, it is not possible to use operator== without passing a Comparator parameter oneself. Another solution would be to allow it but provide a default epsilon in the definition of the two specialization above.

All other operations (>, <=, >=, ==, !=) can be trivially derived (though perhaps not efficiently) from <, for example by deriving from boost::equality_comparable and/or boost::less_than_comparable.

Matthieu M.
+1 for Policy-based Design.
Tomek
I'll look into policy based design. For now I'll take the operator road, thx.
DaClown