Безопасно ли полагаться на неявное продвижение от любого числового типа (unsigned, int, ...) к double?
У меня есть класс шаблонов для графиков, который принимает параметр для типа веса (может быть unsigned, int или double). Кроме того, для сравнения двойников я использую встроенные функции следующего типа:
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);
}
Является ли компаратор в следующем классе скелета безопасным ?
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
};
Могу ли я столкнуться с непредвиденными последствиями, когда тип веса unsigned или int ? Или есть лучший способ реализовать двойное сравнение ?
2 ответа:
Именно для этого и существуют шаблоны.
Я бы предложил реализовать
EpsLess
() внутри класса шаблона, который использует только операторы<
и==
. Что-то вроде:template<typename Type> Compare { public: template<typename Ignore> inline bool EpsLess(Type x, Type y, Ignore epsilon = Ignore()) { return x < y; } };
Тогда специализируй его на двойнике:
template<> Compare<double> { public: inline bool EpsLess(double x, double y, double epsilon = 1.e-10) { return x < y - epsilon; } };
Вы могли бы вызвать его следующим образом:
Это позволит избежать кучи бесполезной работы для недвойственных случаев и перейти к обычному операторуif (Compare<Weight>::EpsEqual(e1.weight, e2.weight))
<
.Ваше домашнее задание, таким образом, состоит в том, чтобы переопределить
EpsEqual
() как сама шаблонная функция, в терминах новогоEpsLess
().
Нет, вы не можете доверять целочисленному двойному преобразованию во всех случаях.
Преобразование целого числа в двойное не всегда может быть выполнено без потери точности. Следовательно, вы можете получить проблемы, если Weight является целочисленным типом, который может содержать большие значения, например size_t
Все 32-битные целые числа могут быть преобразованы без проблем (ака потеря точности).