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)
,条件运算符将看到xvalue,从而从转发的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);
}
答案 0 :(得分:3)
在我看来,你正试图过度简化这个问题。不幸的是,让它完全正确无疑是非常重要的。如果您还没有阅读N2199,现在是时候这么做了。 Rvalue引用继续发展,因此它的min和max的参考实现可能不再完全正确,但它至少应该是一个相当不错的起点。警告:参考实现比您想要的更复杂 lot !
答案 1 :(得分:1)
您不希望完美转发,此处您要返回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