【问题标题】:Why the rvalue reference parameter cannot be passed between functions directly?为什么不能在函数之间直接传递右值引用参数?
【发布时间】:2021-02-24 02:48:27
【问题描述】:

我的代码如下:

#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;
}

当我编译上面显示的代码时,我得到了一些编译错误:

好像B::send函数中的str改成了左值。然后我改了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");
    } 
}; 

一切都很顺利,但是这个程序的输出让我更加困惑。输出如下:

为什么参数 str 是一个右值引用,但我不能在没有 std::move 的情况下直接将它传递给函数 A::sendByRvalue

【问题讨论】:

  • 好问题。不过我建议这样做:对于您的编译错误,最好将它们以书面形式提供,以便其他搜索类似错误的人可能会发现这个问题。为了使其可读,您可以将其格式化为引号。对于这个问题,它并不重要,但社区不喜欢文字图片是 SO 的一般规则。
  • 好建议!让其他人可以通过谷歌搜索相同的错误消息来找到这个问题是个好主意。我试图将这些消息更改为书面格式。但它看起来很奇怪。所以我别无选择,只能粘贴那些图片

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


【解决方案1】:

str 是一个命名的右值引用,在语言中被视为左值。 rvalues 只是 xvalues 或 prvalues,str 两者都不是。

the standard 的注释,关于 xvalue 规则:

一般来说,这条规则的效果是命名的右值引用被视为左值,而对对象的未命名的右值引用被视为xvalue;对函数的右值引用被视为左值,无论是否命名。

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

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

表达式f()f().mstatic_­cast&lt;A&amp;&amp;&gt;(a)a + a 是xvalues。表达式ar 是一个左值。

【讨论】:

  • 哦,非常感谢。我明白你的意思了。关键是右值引用和右值不是一回事。这就是为什么is_rvalue_reference&lt;decltype(str)&gt;::value 为真而str 为左值的原因。
【解决方案2】:

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

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++,它是一个右值,被传递到namename 是一个左值。所以上面的代码基本都是翻译成的。

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++

如果你想要一个简单的方法来检查一个表达式是左值还是右值,你可以试试下面的sn-p

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

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

source

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-27
    • 2020-11-27
    • 2018-09-09
    • 2014-12-20
    • 2021-07-18
    相关资源
    最近更新 更多