7

min 算法通常表示如下:

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

但是,这不允许使用 form 的构造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);
}
4

2 回答 2

3

在我看来,您似乎是在试图过度简化问题。不幸的是,让它完全正确绝对不是微不足道的。如果您还没有阅读N2199,那么现在是阅读的好时机。右值引用继续发展,因此它的 min 和 max 的引用实现可能不再完全正确,但它至少应该是一个相当不错的起点。警告:参考实现比您想要的要复杂得多

于 2010-06-22T17:37:32.580 回答
1

您不想要完美的转发,在这里,您想要返回T&or const T&and never 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
于 2010-06-22T17:37:15.857 回答