23819


以下のコード

[code]

    #include <iostream>
    class foo
    {
    
    };
    
    void f(foo&& r)
    {
        std::cout << "rvalue ref" << std::endl;
    }
    void f(foo& r)
    {
        std::cout << "lvalue ref" << std::endl;
    }
    
    int main()
    {
        foo&& r = foo();
    
        std::cout << "foo() is ";
        f(foo());
        std::cout << "r is ";
        f(r);
    
        return 0;
    }
    
[/code]

において出力結果は

[code]

    foo() is rvalue ref
    r is lvalue ref
    
[/code]

となりました。

[code]

    foo() is rvalue ref
    
[/code]

は理解できますが

[code]

    r is lvalue ref
    
[/code]

となるのは驚きでした。  
r は foo&& すなわちfooへのrvalue referenceのはずですから  
f(r)はf(foo&& r)にオーバーロード解決されるであろうと予測していたからです。

しかし、f(foo& r)にオーバーロード解決されているということは  
r は lvalue referenceということでしょうか？


CC BY-SA 3.0
2016-04-07T06:37:39.427
23817
2016-08-28T02:17:02.140
7844
question
c++ c++11
foo&& r = foo(); rはlvalue reference?


> r は lvalue referenceということでしょうか？

少し違います。 **式`r`** のvalue categoryは **左辺値(lvalue)** であるため、左辺値参照(lvalue
referenece)をとるオーバーロード`f(foo& r)`が選択されたという解釈になります。

紛らわしいのですが、変数の型(type) と 式のvalue categoryは異なる概念です。

  * 変数`r` の型は「右辺値参照(rvalue reference)」(`foo&&`)です。
  * 式`r` のvalue categoryは「左辺値(lvalue)」です。


CC BY-SA 3.0
2016-04-07T06:53:12.597
23819
2016-04-07T06:53:12.597
49
23817
answer


名前を付けた変数は、その名前やメンバーはlvalueです。(もし`class foo`が`int
x`というメンバーが含んでいたら、`foo().x`はrvalueが、`r.x`はlvalueです)

[Value categories -
cppreference](http://en.cppreference.com/w/cpp/language/value_category)

> lvalue
>
> The following expressions are lvalue expressions:
>
> the name of a variable or a function in scope, regardless of type, such as
> `std::cin` or `std::endl`. Even if the variable's type is rvalue reference,
> the expression consisting of its name is an lvalue expression

スタック変数の他には、パラメータのrvalueも実際にlvalueに取り扱われます。

その掟は、以下の誤用を防止します

[code]

    void g(std::unique_ptr<int> q) { /* .. */ }
    
    void f(std::unique_ptr<int>&& p) {
        g(p); // たとえpはrvalue、ここでgのパラメータにmoveされて
        // ...
        g(p); // もう一度pでgを呼び出してしまったら、gのパラメータはnullptrです
    }
    
[/code]

ですから、なるべくrvalue
reference型のスタック変数を宣言しないようにします。パラメータのrvalueそのまま転送したいなら、`std::move`や`std::forward`を使用します。


CC BY-SA 3.0
2016-08-28T02:17:02.140
28532
2016-08-28T02:17:02.140
2020-06-17T08:14:45.997
-1
18621
23817
answer