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
上一篇: 实现一个过滤类加载器
下一篇: 分钟和完美的转发