2012-01-13 9 views
6

私は3つの関数呼び出しを扱う必要があります。私は3つのうちの1つがコンパイルされない理由を理解しようとしています(g ++ -std = C++ 0x)。それが答えだ場合C++での値のバインディングの混乱

// Minimal example to reproduce a compile bug I want to understand. 

#include <iostream> 
#include <string> 

using namespace std; 


void bar(const string &&x) { cout << "bar: " << x << endl; } 

string returns_a_string() { return string("cow"); } 

int main(int argc, char *argv[]) 
{ 
    bar(string("horse"));  // ok 
    bar(returns_a_string()); // ok 
    string aardvark = "aardvark"; 
    bar(aardvark);   // not ok, fails to compile, error in next comment 
    /* 
     rvalue-min.cpp:29:22: error: cannot bind ‘std::string {aka std::basic_string<char>}’ lvalue to ‘const string&& {aka const std::basic_string<char>&&}’ 
     rvalue-min.cpp:10:6: error: initializing argument 1 of ‘void barR(const string&&)’ 
    */ 
} 

この質問は、 C++0x rvalue references - lvalues-rvalue binding、 の線に沿って少しですが、私の謝罪は、私はそれを蒸留することができませんでした。

私が望むのは、任意の種類の文字列で関数bar()を呼び出して動作させることです。 void barR(const string &x)を定義するだけで十分ですが、なぜそれなら理解したいと思います。

3回目の呼び出しが異なる理由を理解してくれてありがとうございました。

+3

*定数*右辺値の参照では、何も役に立たないことに注意してください。通常、 'bar(std :: string &&)'を宣言したいと思うでしょう。 –

+0

@KerrekSB - 良い点 – jma

答えて

14

r値参照パラメータの目的は、オブジェクトがr値であるときに特に検出することです。オブジェクトがr値である場合、関数はそれが再び使用されないことを知っているので、それが望むものであれば何でもできます。 l値がr値の参照にバインドされる可能性がある場合、それは実際には起こっていないことを私が話していたことを意味します。

これらの関数の1つにl値を渡す場合は、std::moveを使用する必要があります。 std::moveを介してオブジェクトをr値の参照を受け取る関数に渡すことは、「ここでこのオブジェクトを取って、それを捨てて、何が起こるのか気にしない」と言うのと同じです。

正しい答えは、パラメータconst参照を作成することです。 r値はconst参照にバインドされていることが完全にうれしいです。移動コンストラクタを除いて、r値の参照パラメータを作成することは、決して正しいことではありません。

+0

この記事に記載されている例には一致しません(具体的には:Ctrl + F "// Line 31")。http://blogs.msdn.com/b/vcblog/archive/2009/02/03 /rvalue-references-c-0x-features-in-vc10-part-2.aspx –

+0

@sftrabbit:そうですが、言語標準(およびその記事のコードを拒否するGCC)にも同意します。 –

+0

ありがとうございます。私は前の記事でこの間違いに気づきましたが、それを確認することに決心しませんでした。 –

4

std::moveを使用する必要があります。これはうまく動作します:

bar(std::move(aardvark)); 
+0

十分に公正ですが、それはクライアントに仕事を課します。しかし、感謝しています。 – jma

+1

@jma:クライアントは、クライアントがオブジェクトの中身を取り除くための関数の明示的な許可を与えているため、クライアントがそれを行う必要があります。 (これはconstが奇妙な理由です)すべてをとるためには(const std :: string&rhs)コードしか持たないようにしてください。 –