9

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

 #include <iostream>
 using namespace std;

 class A {

 };

 A rtByValue() {
return A();
 }

 void passByRef(A &aRef) {
    // do nothing
 }

 int main() {
    A aa;
    rtByValue() = aa;            // compile without errors
    passByRef(rtByValue());      // compile with error 

    return 0;
 }

g++ コンパイラで次のエラーが発生します。

d.cpp: In function ‘int main()’:
d.cpp:19:23: error: invalid initialization of non-const reference of type ‘A&’ from an rvalue of type ‘A’
d.cpp:12:6: error: in passing argument 1 of ‘void passByRef(A&)’

非 const 参照の引数として右辺値を渡すことはできないと書かれていますが、コードが示すように、なぜこの右辺値に代入できるのかについて混乱しています。

4

3 に答える 3

10

左辺値参照を期待する関数に右辺値を渡すrtByValue()と、左辺値参照引数を右辺値から初期化する必要があるため、機能しません。§8.5.3/5 では、左辺値参照を初期化する方法について説明しています。完全には引用しませんが、基本的には、左辺値参照を初期化できると述べています。

  • 別の左辺値参照から
  • または中間型の左辺値参照に変換できるもの
  • または右辺値から、ただし初期化する左辺値参照が const 参照である場合のみ

初期化する必要がある引数は const 参照ではないため、これは適用されません。

一方で、

rtByValue() = aa; 

つまり、次の理由により、一時オブジェクトへの割り当てが可能です。

(§3.10/5) オブジェクトを変更するには、オブジェクトの左辺値が必要です。ただし、特定の状況下では、クラス型の右辺値を使用してその指示対象を変更することもできます。[ 例: オブジェクト (9.3) に対して呼び出されるメンバー関数は、オブジェクトを変更できます。— 終了例 ]

したがって、これAはクラス型であり、(暗黙的に定義された) 代入演算子がメンバー関数であるためにのみ機能します。(詳細については、この関連する質問を参照してください。)

(したがって、rtByValue()たとえば が返された場合int、代入は機能しません。)

于 2013-04-05T03:06:54.483 に答える
2

右辺値で呼び出すのが理にかなっているような operator= をオーバーライドできる (ただしすべきではありません!) ためです。次のコードを検討してください。

#include<iostream>

using namespace std;

class foo;

foo* gotAssigned = NULL;
int assignedto = -1;

class foo {
public:
  foo(int v) : val(v) {}
  foo& operator=(int v) {
    assignedto=v;
    gotAssigned = this;
    val = v;
    return *this;
  }
  int val;
};

foo theFoo(2);

foo returnTheFooByValue() {
  return theFoo;
}

main() {
  returnTheFooByValue()=5;
  cout << "[" << assignedto << "] " << theFoo.val << " versus " << gotAssigned->val << endl;
}

それでは、いくつかの方法でコンパイルしましょう。

$ g++ -O0 -o rveq rveq.cc && ./rveq
[5] 2 versus 5
$ g++ -O1 -o rveq rveq.cc && ./rveq
[5] 2 versus 2
$ g++ -O4 -o rveq rveq.cc && ./rveq
[5] 2 versus -1218482176

同じ結果が得られるとは約束できません。

ご覧のとおり、割り当ては行われますが、割り当てられたオブジェクトを使用しようとすると、実装固有の動作が発生します。

ちなみに、これはユーザー定義型にのみ適用されます。このコード:

int v(){
  return 2;
}

main(){
  v()=4;
}

コンパイルしません。

于 2013-04-05T03:25:26.033 に答える