4

私のコードは次のとおりです。

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

上記のコードをコンパイルすると、いくつかのコンパイル エラーが発生しました。 ここに画像の説明を入力

strinB::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");
    } 
}; 

すべてうまくいきますが、このプログラムの出力は私をさらに混乱させました。出力は次のとおりです。 ここに画像の説明を入力

パラメーター str が右辺値参照であるのに、引数A::sendByRvalueなしで直接関数に渡すことができないのはなぜstd::moveですか?

4

2 に答える 2

4

str言語で左辺値として扱われる、名前付きの右辺値参照です。rvalues は xvalues または prvalues のみであり、strどちらでもありません。

xvalue ルールに関する標準からのメモ:

一般に、このルールの効果は、名前付きの右辺値参照が左辺値として扱われ、オブジェクトへの名前のない右辺値参照が 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は xvalues です。式arは左辺値です。

于 2020-11-12T05:05:33.530 に答える
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++

式が左辺値か右辺値かを確認する簡単な方法が必要な場合は、以下のスニペットを試すことができます

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

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

ソース

于 2020-11-12T05:15:58.293 に答える