C++ なんとかvalues
C++には lvalue やら rvalue やらたくさんありますが、混乱している人もいるかもしれないのでめちゃくちゃ簡単にまとめておきます。
多分間違ってるところがあると思うので、その時は教えて下さい。よろしくお願いします。
lvalue
簡単にいえば左辺にして代入できるもののことです。*1
named object (名前があるオブジェクト)と言ったほうがいいかもしれませんね。
( int& foo() { return i; } foo() = 1; とか書けますよね。)
template <typename T> void f(T& t) { std::cout << "T&" << std::endl; } // lvalue reference template <typename T> void f(T&& t) { std::cout << "T&&" << std::endl; } // rvalue reference int i=0; int& foo() { return &i; } int main() { int xv = 0; // 0 is rvalue(prvalue) f(xv); // T& xv is lvalue f(foo()); // T& foo() is lvalue }
xvalue
C++ の規格より引用します。(§5 の最初あたりですね)
以下の expression はすべて xvalue となります。
- 明示的か非明示的かどうかにかかわらず、戻り値にオブジェクトへの rvalue reference をもつ関数呼び出しの結果
- rvalue reference へのキャスト
- オブジェクトの reference でも static でもないデータメンバへのアクセス
- 1つ目のオペランドが xvalue で、2つ目のオペランドがデータメンバへのオペランドである .* pointer-to-member expression ( ->* だと一つ目のオペランドが xvalue でないのでダメ? )
※ pointer-to-member expression とは
class C { public: constexpr C() : m_(0) {} void disp() { std::cout << m_ << std::endl; } int m_; }; int main() { C c; C* pc = new C(); int C::* pm = &C::m_; c.*pm = 10; pc->*pm = 20; c.disp(); // 10 pc->disp(); // 20 delete pc; }
c.*pm と pc->*pm が pointer-to-member expression です。const object の mutable メンバには使えないとか色々ありますが、詳しくは手元の規格を参照してください。(§5.5 pointer-to-member expression)
一般的に,この規則によって named rvalue references *2 は lvalues として扱われ、unnamed rvalue references to objects*3は xvalues として扱われます。また、関数への rvalue references は名前があるかないかにかかわらず lvalues として扱われます。
struct A { int m; }; A&& operator+(A, A); A&& f(); A a; A&& ar = static_cast<A&&>(a);
f(), f().m, static_cast(a), a + a という expression はすべて xvalue で、ar は lvalue となります。
prvalue(pure rvalue)
xvalue でない rvalue のことです。例えば、戻り値に参照型を持たない関数の呼出の結果は prvalue です。他にも、0 や true 等の文字列以外のリテラルも prvalue です。
prvalue のメンバ変数も prvalue だったり。
【追記 2013/05/16】ラムダ式も prvalue ですね。
template <typename T> void f(T& t) { std::cout << "T&" << std::endl; } // lvalue reference template <typename T> void f(T&& t) { std::cout << "T&&" << std::endl; } // rvalue reference int i=0; int bar() { return 1; } struct hoge { int m; }; int main() { f(1); // T&&: 1 is prvalue f(bar()); // T&&: bar() is prvalue f(false); // T&&: false is prvalue hoge().m; // prvalue }
glvalue
lvalue または xvalue の事です。(すみませんこれ以上の説明が思い浮かびませんでした。)
rvalue
大雑把に言いますと、一時オブジェクトのことです。xvalue と prvalue をまとめたものとして考えられます。
unnamed object(名前がないオブジェクト)とも言えます。
C++11の rvalue reference とは一時オブジェクトを保持するためのものですが、
std::string str1 = "bar"; std::string&& str2 = "foo"; std::string&& str3 = str1; // Error! str1 is lvalue std::string&& str4 = str2; // Error! str2 is lvalue
3行目は明らかにエラーですね。
4行目で str1 は名前を持ってしまっている(一時オブジェクトでない)ので rvalue ではなく lvalue となり、エラーとなります。
最後に
もっと詳しい解説は、ググるかなにかで調べてもらえれば同志の方がたくさん書かれていらっしゃいますので、そちらに丸投げさせて頂きます。あくまで簡単なまとめということでお願いします。