C++0x中将const RValue引用作为函数参数

27

我试图理解为什么有人会编写一个接受const rvalue引用的函数。

在下面的代码示例中,const rvalue引用函数(返回“3”)有什么用途。 并且为什么重载决议喜欢const Rvalue而不是const LValue引用函数(返回“2”)。

#include <string>
#include <vector>
#include <iostream>

std::vector<std::string> createVector() { return std::vector<std::string>(); } 

//takes movable rvalue
void func(std::vector<std::string> &&p) { std::cout << "1"; }

//takes const lvalue
void func(const std::vector<std::string> &p)  { std::cout << "2"; }

//takes const rvalue???
//what is the point of const rvalue? if const I assume it is not movable?
void func(const std::vector<std::string> &&p) { std::cout << "3"; }

int main()
{
    func(createVector());
    return 0;
}

VC++10具有符合标准的移动语义和重载解析,但在gcc上应该是相同的。 - MW_dev
rvalue引用到const有什么用处? - Johannes Schaub - litb
@litb:这只是部分重复,另一个问题并没有真正解决关于重载决议的问题。 - reko_t
可能是Do rvalue references to const have any use?的重复问题。 - Jonathan Mee
2个回答

30
更偏向于与lvalue引用绑定,同样也更倾向于与rvalue引用绑定。可修改的表达式弱化地偏向于与非const引用绑定。 在进行重载决议时,会检查是否有接受rvalue引用的重载,因为这是首选的。在这种情况下,由于表达式是可修改的rvalue,因此rvalue引用重载胜出。 实际上有用途,它们可以用于确保某些东西不会绑定到rvalue上。请记住,rvalue绑定到const lvalue引用,因此如果你这样做:
template <typename T> void foo(const T& bar) { /* ... */ }

并使用以下方式调用该函数:

foo(createVector());

可以正常工作。然而,有时希望确保只能将左值传递给函数(这是例如 std::ref 的情况)。您可以通过添加重载函数来实现:

template <typename T> void foo(const T&&) = delete;

记住,rvalue 强烈倾向于绑定到 rvalue 引用,可修改的表达式则倾向于弱绑定到非 const 引用。由于我们拥有一个 const rvalue 引用,这基本上意味着每个单独的 rvalue 将绑定到它,因此如果你尝试将一个 rvalue 传递给 foo(),你的编译器将会报错。这是实现这种功能的唯一方式,因此有时是有用的。


谢谢您详尽的回答。当您说:“LValues强烈倾向于绑定到lvalue引用”时,您是什么意思?我不认为LValues可以绑定到RValues。我是否误解了您的意思? - MW_dev
1
Lvalues可以绑定到const rvalue引用。任何东西都可以绑定到const lvalue引用以及const rvalue引用。 - reko_t
3
这并没有说明为什么const右值本身有用,只是解释为什么你可能需要一个const右值引用。 - Puppy
2
@reko_t:对你的回答进行了微小的更正。这并不改变你的结论。但是,lvalue不能绑定到const rvalue引用。原来它们可以。但是规则在2009年春季被更改,以便它们不能。这个规则的一个明显例外是针对形式为T&&(非const)的模板参数进行推导时。这种形式是特殊的,并且将绑定到lvalue(否则完美转发就行不通了)。话虽如此,我完全同意你的用例:https://dev59.com/PW445IYBdhLWcg3wTIZf#4940642 - Howard Hinnant
1
DeadMG,这就是OP所问的:“我想知道为什么有人会编写一个接受const rvalue引用的函数”。 - reko_t
显示剩余2条评论

2

重载决议更喜欢const rvalue而不是const lvalue,因为它是一个rvalue并且您将其绑定到一个rvalue引用上,但在两种情况下都必须添加const,因此rvalue引用肯定更受欢迎。

这样的事情通常是没有意义的-最好让它们绑定到const lvalue重载。const rvalues没有任何实际用途。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接