为什么右值引用参数不能直接在函数之间传递?

时间:2020-11-12 04:52:29

标签: c++ rvalue-reference rvalue lvalue-to-rvalue pass-by-rvalue-reference

我的代码如下:

#include <iostream>
using namespace std;

class A{
public:
    void sendByRvalue(string&& str){
        cout << str << endl;
    }
};

class B{
private:
    A a;
    void send(string&& str){
        a.sendByRvalue(str);
    }
public:
    void run(const string& str){
        send("run " + str + "\n");
    } 
}; 

int main(void){
    string str("hello world");
    B b;
    b.run(str);
    return 0;
}

编译上面显示的代码时,出现一些编译错误: enter image description here

似乎str中的B::send已更改为lvalue。然后,我更改B::send的实现,例如:

class B{
private:
    A a;
    void send(string&& str){
        cout << boolalpha << is_rvalue_reference<decltype(str)>::value << endl;
        a.sendByRvalue(std::move(str));
    }
public:
    void run(const string& str){
        send("run " + str + "\n");
    } 
}; 

一切顺利,但是该程序的输出使我更加困惑。输出如下: enter image description here

为什么参数str是右值引用,但是没有A::sendByRvalue我不能将其直接传递给函数std::move吗?

2 个答案:

答案 0 :(得分:4)

str是一个命名的右值引用,该引用在语言中被视为左值。 rvalue只是xvalue或prvalue,str都不是。

来自the standard的关于xvalue规则的注释:

通常,此规则的作用是将已命名的右值引用视为左值,将对对象的未命名的右值引用视为左值;不论是否命名,对函数的右值引用均视为左值。

struct A {
int m;
};
A&& operator+(A, A);
A&& f();

A a;
A&& ar = static_cast<A&&>(a);

表达式f()f().mstatic_­cast<A&&>(a)a + a是x值。表达式ar是一个左值。

答案 1 :(得分:1)

我将做一个简单的例子来解释

void bar(std::string&& name) {
    std::cout << "Bar: " << name << std::endl;
}

void foo(std::string&& name) {
    bar(name);
}


int main() {
    foo("C++");
}

这与您提供的示例大致相同。在foo()中, name是左值。临时字符串C++ rvalue ,它被传递到name中。 name是左值。因此,上面的代码基本上被翻译成。

void bar(std::string&& name) {
    std::cout << "Bar: " << name << std::endl;
}

int main()
{
    std::string foo{ "C++" };
    bar(foo);
}

现在看来问题出在哪里。


我写了这个简单的程序来帮助您更好地理解

void foo(const std::string& name) {
    std::cout << "Passed as lvalue ref: " << name << std::endl;
}

void foo(std::string&& name) {
    std::cout << "Passed as rvalue ref: " << name << std::endl;
}

我们将使用此函数调用

void bar(std::string&& name) {
    foo(name);
}

int main()  {
    bar("C++");
}

作为左值引用传递:C ++

这证明了我的观点,现在如果我们使用std::move()会怎样?

void bar(std::string&& name) {
    foo(std::move(name));
}

int main()  {
    bar("C++");
}

作为右值引用传递:C ++

如果您想要一种简单的方法来检查表达式是左值还是右值,则可以尝试以下代码段

template <typename T>
constexpr bool is_lvalue(T&) {
    return true;
}

template <typename T>
constexpr bool is_lvalue(T&&) {
    return false;
}

source

相关问题