мин и идеальная пересылка - PullRequest
7 голосов
/ 22 июня 2010

Алгоритм min обычно выражается так:

template <typename T>
const T& min(const T& x, const T& y)
{
    return y < x ? y : x;
}

Однако это не допускает конструкции вида min(a, b) = 0.Вы можете добиться этого с помощью дополнительной перегрузки:

template <typename T>
T& min(T& x, T& y)
{
    return y < x ? y : x;
}

Я хотел бы объединить эти две перегрузки с помощью идеальной пересылки:

template <typename T>
T&& min(T&& x, T&& y)
{
    return y < x ? std::forward<T>(y) : std::forward<T>(x);
}

Однако g ++ 4.5.0 выплевываетпредупреждение для min(2, 4), что я возвращаю ссылку на временный.Я сделал что-то не так?


Хорошо, я понял.Проблема с условным оператором.В моем первом решении, если я вызову min(2, 4), условный оператор видит значение x и, таким образом, перемещается из перенаправленного x, чтобы создать временный объект.Конечно, было бы опасно возвращать это по ссылке!Если я перешлю целое выражение вместо x и y отдельно, компилятор больше не будет жаловаться:

template <typename T>
T&& min(T&& x, T&& y)
{
    return std::forward<T>(y < x ? y : x);
}

Хорошо, я избавился от ссылок на арифметические типы:)

#include <type_traits>

template <typename T>
typename std::enable_if<std::is_arithmetic<T>::value, T>::type
min(T x, T y)
{
    return y < x ? y : x;
}

template <typename T>
typename std::enable_if<!std::is_arithmetic<T>::value, T&&>::type
min(T&& x, T&& y)
{
    return std::forward<T>(y < x ? y : x);
}

Ответы [ 2 ]

3 голосов
/ 22 июня 2010

Мне кажется, ты пытаешься упростить проблему.К сожалению, получить его полностью правильно, определенно нетривиально.Если вы не читали N2199 , сейчас самое время сделать это.Ссылки на Rvalue продолжают развиваться, поэтому его реализация min и max, вероятно, уже не совсем правильная, но, по крайней мере, должна быть довольно приличной отправной точкой.Предупреждение: эталонная реализация на лот более сложная, чем вам понравится!

1 голос
/ 22 июня 2010

Вы не хотите совершенную пересылку, здесь вы хотите вернуть либо T&, либо const T&, но никогда T&&.std::forward предназначен для передачи одного из ваших параметров в другую функцию, а не для возвращаемых значений.

Я думаю, что вам нужно:

template <typename T>
min(T&& x, T&& y) -> decltype(x)
{
    return y < x ? y : x;
}

РЕДАКТИРОВАТЬ, чтобы избежать висячих проблем со ссылками:

template <typename T>
struct dedangle { typedef T type; }

template <typename T>
struct dedangle<const T&> { typedef T type; }

template <typename T, typename U>
min(T&& x, U&& y) -> dedangle<decltype(0?y:x)>::type
{
    return y < x ? y : x;
}

// dedangle is re-usable by max, etc, so its cost is amortized
...