最小和完美的转发

fre*_*low 7 c++ templates forwarding rvalue-reference c++11

min算法通常表示如下:

template <typename T>
const T& min(const T& x, const T& y)
{
    return y < x ? y : x;
}
Run Code Online (Sandbox Code Playgroud)

但是,这不允许表单的构造min(a, b) = 0.您可以通过额外的重载实现这一目标:

template <typename T>
T& min(T& x, T& y)
{
    return y < x ? y : x;
}
Run Code Online (Sandbox Code Playgroud)

我想做的是通过完美转发统一这两个重载:

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

但是,g ++ 4.5.0会发出警告,min(2, 4)表示我返回对临时的引用.我做错什么了吗?


好的,我明白了.问题在于条件运算符.在我的第一个解决方案中,如果我调用min(2, 4)条件运算符,则会看到xvalue,从而从转发中移动x以生成临时对象.当然,通过引用返回它是危险的!如果我转了整个表达,而不是xyseperately,编译器不会再抱怨:

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

好的,我摆脱了算术类型的引用:)

#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);
}
Run Code Online (Sandbox Code Playgroud)

Jer*_*fin 3

在我看来,你似乎试图将问题过于简单化。不幸的是,要使其完全正确绝对不是一件容易的事。如果您还没有阅读N2199,现在是阅读的好时机。右值引用不断发展,因此它的 min 和 max 的参考实现可能不再完全正确,但它至少应该是一个相当不错的起点。警告:参考实现比您想象的要复杂得多