【发布时间】:2010-06-22 17:28:49
【问题描述】:
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);
}
【问题讨论】:
-
嗯,在我看来,最后一个示例也根据 FCD 创建了一个临时文件。但这似乎很奇怪:它似乎创建了将
int&&绑定到intxvalue 的临时对象?!我认为 xvalues 是匿名右值引用,可以由右值引用绑定而无需创建临时对象?您修改后的代码似乎也发生了同样的情况,不是吗?返回类型为int&&,返回表达式为intxvalue。为什么编译器不再警告它? -
如果我正确阅读了
8.5.3,它会说这会在将引用绑定到 xvalue 时创建一个 int 临时变量:int x = 0; int &&rx = (int&&)x;同样在使用std::move时。我认为这不是目的。 -
@Johannes:你具体说的是 8.5.3 的哪一部分?
-
@Fred 所有规则 :) 这一次,最后一个子弹适用,它创建了一个临时的。
-
int不是类类型。所以为int创建了一个临时的。我认为这是一个缺陷。
标签: c++ templates c++11 forwarding rvalue-reference