min and perfect forwarding

The min algorithm is normally expressed like this:

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

However, this does not allow constructs of the form min(a, b) = 0 . You can achieve that with an additional overload:

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

What I would like to do is unify these two overloads via perfect forwarding:

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

However, g++ 4.5.0 spits out a warning for min(2, 4) that I return a reference to a temporary. Did I do something wrong?


Okay, I get it. The problem is with the conditional operator. In my first solution, if I call min(2, 4) the conditional operator sees an xvalue and thus moves from the forwarded x to produce a temporary object. Of course it would be dangerous to return that by reference! If I forward the whole expression instead of x and y seperately, the compiler does not complain anymore:

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

Okay, I got rid of the references for arithmetic types :)

#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);
}

It looks to me like you're trying to oversimplify the problem. Unfortunately, getting it entirely correct is decidedly non-trivial. If you haven't read N2199, now would be a good time to do so. Rvalue references continue to evolve, so its reference implementation of min and max probably isn't exactly right anymore, but it should at least be a pretty decent starting point. Warning: the reference implementation is a lot more complex than you're going to like!


You don't want perfect forwarding, here, you want to return either T& or const T& and never T&& . std::forward is designed for passing one of your parameters along to another function, not for return values.

I think what you want is:

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

EDIT to avoid dangling reference problem:

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
链接地址: http://www.djcxy.com/p/46386.html

上一篇: 实现一个过滤类加载器

下一篇: 分钟和完美的转发