简体   繁体   English

如果可能,C ++通过rvalue引用传递参数,否则复制左值引用

[英]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.

相关问题 rvalue或lvalue(const)引用参数 - rvalue or lvalue (const) reference parameter 在可能的情况下,C ++总是更喜欢rvalue引用转换运算符而不是const lvalue引用吗? - Will C++ always prefer an rvalue reference conversion operator over const lvalue reference when possible? 为什么右值引用作为左值引用传递? - Why rvalue reference pass as lvalue reference? 如何将右值引用参数传递给 C++ 中的模板运算符() function? - How to pass a rvalue reference parameter to a template operator() function in C++? 在 C++ 中将右值引用转换为临时参数为 const 左值返回的正确方法 - Correct way to convert rvalue reference to temporary parameter to const lvalue return in C++ C ++,为什么可以将右值传递给以左值引用为参数的函数 - C++, why can you pass rvalue to a function which takes lvalue reference as argument 右值引用上的左值引用 - lvalue reference on rvalue reference C ++ 11:为什么将右值引用参数隐式转换为左值 - C++11: Why rvalue reference parameter implicitly converted to lvalue C ++,在函数中使用const左值和右值引用 - C++, take const lvalue and rvalue reference in a function C ++通用引用。 为什么右值引用变成左值? - C++ universal references. Why rvalue reference becomes lvalue?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM