C++ 最小和完美转发

C++ 最小和完美转发,c++,templates,c++11,forwarding,rvalue-reference,C++,Templates,C++11,Forwarding,Rvalue Reference,最小算法通常表示为: template <typename T> const T& min(const T& x, const T& y) { return y < x ? y : x; } 我想通过完美转发来统一这两个重载: template <typename T> T&& min(T&& x, T&& y) { return y < x ? std::forward

最小算法通常表示为:

template <typename T>
const T& min(const T& x, const 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);
}

好的,我去掉了算术类型的引用:)

#包括
模板
typename std::enable_if::type
最小值(T x,T y)
{
返回y::type
最小值(T&x、T&y)
{
返回标准:正向(y
您不想要完美的转发,在这里,您想要返回
t&
const t&
,而决不返回
t&
std::forward
设计用于将一个参数传递给另一个函数,而不是返回值

我想你想要的是:

template <typename T>
min(T&& x, T&& y) -> decltype(x)
{
    return y < x ? y : x;
}
模板
最小值(T&&x,T&&y)->decltype(x)
{
返回y
编辑以避免悬空引用问题:

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
模板
结构dedangle{typedef T type;}
模板
结构dedangle{typedef T type;}
模板
最小值(T&&x,U&&y)->dedangle::type
{
返回y
在我看来,你似乎试图将问题过于简单化。不幸的是,让它完全正确绝非易事。如果你还没有读过,现在是读的好时机。右值引用仍在不断发展,因此其min和max的引用实现可能不再完全正确,但至少应该是一个相当不错的起点。警告:参考实现比您希望的要复杂得多

我不确定是哪种类型的
decltype(x)
,但要么是
T
,这根本不是我想要的,要么是
T&
,这是你说我不应该做的。对吗?本标准第14.8.2.1节【临时扣除调用】描述了模板函数参数上发生的转换
decltype(x)
可以很容易地成为
int&
const int&
,而返回类型不经过此过程。查看标准中该部分的示例3。我不同意,
decltype(x)
总是与
T&
相同。您可以通过插入行
static_assert(std::is_same::value,“哎哟”)
转换到
min
函数模板中。因此,因为转换是在
T
上进行的,而不是参数
T&&x
,所以它毕竟会影响返回类型?如果继续并返回
T&
,但忽略
std::forward
?那将不起作用,因为如果我调用
min(2,4)
,那么
T
就是
int&
,并且由于引用折叠规则,
T&
也是
int&
。所以我会尝试将
int&
绑定到
y
这是一个左值(因为y和x与每个形式参数一样都是左值),但右值引用不绑定左值。看起来该建议被拒绝了。知道为什么吗?@jalf:我怀疑人们瞥了一眼参考实现,吓得尖叫着跑掉了。:-)@jalf yep,请看“你试图将问题过于简化”->我更喜欢过于简化的问题而不是过于复杂的解决方案:)@FredOverflow:别误会——我想几乎每个人都同意N219中提出的“解决方案”过于复杂。OTOH,它并不是因为反常而过于复杂——虽然论文没有被接受,但问题没有改变,语言中也没有添加任何东西来让更简单的解决方案完成同样的任务。基本上,每个简单的解决方案都会有问题和缺点。嗯,在我看来,最后一个例子也会根据FCD创建一个临时的解决方案。但这似乎很奇怪:它似乎创建了将
int&
绑定到
int
xvalue的临时变量?!我认为xvalues是匿名的右值引用,可以被右值引用绑定,而无需创建临时值?你修改过的代码似乎也是这样,不是吗?返回类型为
int&
,返回表达式为
int
xvalue。为什么编译器不再为此发出警告?如果我正确阅读
8.5.3
,它会说在将引用绑定到xvalue时会创建一个int临时值:
int x=0;int&&rx=(int&&x)使用
std::move
时也是如此。我想这不是你的本意。@Johannes:你具体说的是8.5.3的哪一部分?@Fred所有规则:)这一次,最后一个项目符号会创建一个临时的。
int
不是类类型。因此,对于
int
将创建一个临时文件。我认为这是一个缺陷。
#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);
}
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