我得到了这个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 ...
};
运算符,基本上是用于比较的运算符,使用简单的compare-the-member-object方法,如:
friend bool operator== (const Point3DBase<U> &lhs, const Point3DBase<U> rhs) { return (lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z); }
然后我发现,对于双值的比较,简单相等方法不是很有用,因为双值应该与误差范围进行比较。引入误差范围的最佳方法是什么?我认为epsDouble类型作为模板参数,但我无法弄清楚如何实现这一点。
编辑:
我见过链式输出流运算符,它调用输出流运算符类型的输出流运算符...有没有办法将比较委托给表示浮点类型的自定义类型?
答案 0 :(得分:3)
如果你想为给定浮动类型的所有实例提供一个epsilon值,它实际上非常简单:
template <>
bool operator<(const Point3DBase<double>& lhs, const Point3DBase<double>& rhs)
{
}
如果没有,那么我将引导您走向基于政策的设计,正如Alexandrescu所示:
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
。< / p>
答案 1 :(得分:1)
是的,您不能拥有浮点类型的模板参数。您可以使用int参数,告诉epsilon值的负10基本日志,例如值为3意味着0.001。
答案 2 :(得分:1)
如果你想掌握epsilon,你可以定义一个double的包装类,它在比较这个类的实例时会处理这个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
};