I have a template class for graphs that takes a parameter for the weight type (could be unsigned, int or double). Also, for comparing doubles I use inline functions of the following type:
inline bool EpsLess(double x, double y, double epsilon = 1.e-10)
{
return x < y - epsilon;
}
inline bool EpsEqual(double x, double y, double epsilon = 1.e-10)
{
return !EpsLess(x,y) && !EpsLess(y,x);
}
Is the comparator in the following class skeleton safe ?
template <typename Weight>
class Graph
{
struct Edge
{
std::string from;
std::string to;
Weight weight;
};
struct LargestWeight
{
bool operator() (const Edge& e1, const Edge& e2) const
{
if (EpsEqual(e1.weight == e2.weight))
if (e1.from == e2.from)
return e1.to < e2.to;
else
return e1.from < e2.from;
return EpsLess(e2.weight, e1.weight);
}
};
// .. other stuff
};
Can I encounter unforeseen consequences when Weight type is unsigned or int ? Or is there a better way to implement the double comparison ?
This is exactly what templates are for.
I would suggest that you implement EpsLess
() inside a template class that uses just the <
and ==
operators. Something like:
template<typename Type> Compare {
public:
template<typename Ignore>
inline bool EpsLess(Type x, Type y, Ignore epsilon = Ignore())
{
return x < y;
}
};
Then specialize it for a double:
template<> Compare<double> {
public:
inline bool EpsLess(double x, double y, double epsilon = 1.e-10)
{
return x < y - epsilon;
}
};
You would invoke it like this:
if (Compare<Weight>::EpsEqual(e1.weight, e2.weight))
This will avoid a bunch of useless work for non-double cases, and get devolved to just an ordinary <
operator.
Your homework assignment, then, is to reimplement EpsEqual
() as a template function itself, in terms of the new EpsLess
().