[英]C++ pass parameter by rvalue reference if possible, otherwise copy the lvalue reference
With rvalue references, many redundant copies may be elided, but that seems to require me to write the same function multiple times (one for an rvalue reference, one for a const
lvalue reference). 使用rvalue引用时,可能会省略许多冗余副本,但这似乎要求我多次写入相同的函数(一个用于右值引用,一个用于
const
值左引用)。 But the standard library seems to only need to declare some functions once. 但标准库似乎只需要声明一些函数。
For example: 例如:
#include <iostream>
#include <tuple>
void foo(int&& x){
x = 2;
}
int main()
{
int x = 1;
foo(x); // compile error
std::make_tuple(x); // ok
std::cout << x << std::endl;
}
Calling foo(x)
is a compile error, because I cannot convert implicitly from int
to int&&
. 调用
foo(x)
是一个编译错误,因为我无法从int
隐式转换为int&&
。 But I am perplexed as to why std::make_tuple
would work. 但我很困惑为什么
std::make_tuple
会起作用。 The reference says that it only accepts rvalue reference parameters. 该参考文献表明它只接受右值参考参数。 It also seems to not make copies when the value passed into it is an ravlue reference, but it would make a copy (as most would expect) when used as in my sample above.
当传入它的值是ravlue引用时,它似乎也不会复制,但是当我在上面的示例中使用它时,它会复制(正如大多数人所期望的那样)。
How can I make foo
work like this? 我怎么能让
foo
像这样工作?
The reference says that it only accepts rvalue reference parameters.
该参考文献表明它只接受右值参考参数。
No, this is forwarding reference , which could serve as both lvalue reference and rvalue reference, according to the value category of the passed-in argument. 不,这是转发引用 ,根据传入参数的值类别,它可以作为左值引用和右值引用。
How can I make
foo
work like this?我怎么能让
foo
像这样工作?
The point of declaring a forwarding reference is (1) type deduction is necessary, that means you need to make foo
a function template here; 声明转发引用的要点是(1)类型推导是必要的,这意味着你需要在这里使
foo
成为一个函数模板; (2) the parameter x
has the exact form of T&&
for the template parameter T
. (2)参数
x
具有模板参数T
的精确形式T&&
。 eg 例如
template <typename T>
void foo(T&& x){
x = 2;
}
then 然后
int x = 1;
foo(x); // lvalue passed, T is deduced as int&, parameter's type is int&
foo(1); // rvalue passed, T is deduced as int, parameter's type is int&&
Note this is true for std::make_tuple
too, even it's using template parameter pack. 请注意,对于
std::make_tuple
也是如此,即使它使用模板参数包也是如此。 And better to bear in mind that even forwarding reference looks like rvalue reference but they're different things. 更好的是要记住,即使转发参考看起来像右值参考,但它们是不同的东西。
BTW: std::forward is usually used with forwarding reference to preserve the value category of the argument eg when forwarding it to other functions. BTW: std :: forward通常与转发引用一起使用,以保留参数的值类别,例如将其转发给其他函数时。
std::make_tuple
works because the function doesn't actually take a rvalue reference like foo
does. std::make_tuple
有效,因为该函数实际上并不像foo
那样采用右值引用。 std::make_tuple
takes a object in the form of T&&
and since T
is a template type it makes it a forwarding reference, not a rvalue reference. std::make_tuple
采用T&&
形式的对象,因为T
是模板类型,所以它使它成为转发引用,而不是右值引用。 A forwarding reference can bind to lvalues and rvalues where as a rvalue reference can only take a rvalue. 转发引用可以绑定到左值和右值,其中右值引用只能采用右值。 To make
foo
the same you would need 使
foo
与你需要的一样
template<typename T>
void foo(T&& bar)
{
bar = 2;
}
Would this work for you? 这对你有用吗?
#include <iostream>
#include <tuple>
void foo(int&& x){
std::cout<<"rvalue"<<std::endl;
x = 2;
}
void foo(int& x){
std::cout<<"lvalue"<<std::endl;
x = 2;
}
int main()
{
int x = 1;
foo(x); // no compile error anymore
foo(std::move(x)); // now r-value is being used
std::make_tuple(x); // ok
std::cout << x << std::endl;
}
The difference is a result of a rather subtle overload of the &&
operator when it is used with a template parameter: 差异是
&&
运算符与模板参数一起使用时相当微妙的重载的结果:
template<typename foo>
void bar(foo &&baz)
This is not an rvalue reference. 这不是右值参考。 It is a forwarding reference.
它是转发参考。 When the template gets resolved,
baz
is going to be either an lvalue or an rvalue reference, depending on the call situation. 当模板得到解析时,
baz
将是左值或右值引用,具体取决于调用情况。
This is why you will see the C++ library provide what appears to be a single template, that works in both lvalue and rvalue contexts. 这就是为什么你会看到C ++库提供看似单个模板的原因,它在lvalue和rvalue上下文中都有效。
But forwarding references occur in templates only. 但转发引用仅出现在模板中。 In a non-template declaration:
在非模板声明中:
void bar(int &&baz)
This is always an rvalue reference, and can only be used in rvalue contexts. 这始终是rvalue引用,并且只能在rvalue上下文中使用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.