Безопасно ли полагаться на неявное продвижение от любого числового типа (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 3

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-битные целые числа могут быть преобразованы без проблем (ака потеря точности).