代码之家  ›  专栏  ›  技术社区  ›  fredoverflow

最小和完美的转发

  •  7
  • fredoverflow  · 技术社区  · 15 年前

    最小算法通常如下所示:

    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);
    }
    
    2 回复  |  直到 15 年前
        1
  •  3
  •   Jerry Coffin    15 年前

    在我看来,你好像在试图把问题过于简单化。不幸的是,完全正确的解决方案绝对是不平凡的。如果你没读过 N2199 现在是这样做的好时机。右值引用继续发展,因此其最小值和最大值的引用实现可能不再完全正确,但至少应该是一个相当不错的起点。警告:引用实现是 许多 比你想的复杂!

        2
  •  1
  •   Ben Voigt    15 年前

    你不想要 很完美 转发,这里,您想返回 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