このコードを検討してください:
_struct foo
{
int a;
};
foo q() { foo f; f.a =4; return f;}
int main()
{
foo i;
i.a = 5;
q() = i;
}
_
Clangでさえ、コンパイラはそれについて文句を言いません。 q() = ...
行が正しいのはなぜですか?
いいえ、関数の戻り値は、それが参照(C++ 03)である場合に限り、l値です。 (5.2.2 [expr.call]/10)
返される型が基本型である場合、これはコンパイルエラーになります。 (5.17 [expr.ass]/1)
これが機能する理由は、クラスタイプのr値でメンバー関数(非const
メンバー関数でも)を呼び出すことが許可されており、foo
の割り当てが実装定義のメンバー関数であるためです。 : foo& foo::operator=(const foo&)
。条項5の演算子の制限は、組み込み演算子、(5 [expr]/3)にのみ適用されます。オーバーロード解決によってオペレーターのオーバーロードされた関数呼び出しが選択された場合、その関数呼び出しの制限が適用されます。代わりに。
これが、クラスタイプのオブジェクトをconst
オブジェクト(例:const foo q();
)として返すことが推奨される場合がある理由ですが、これはC++ 0xで悪影響を及ぼし、移動セマンティクスを阻害する可能性があります。彼らがすべきように働くことから。
構造体を割り当てることができ、q()
はstruct foo
のコピーを返すため、返された構造体を指定された値に割り当てます。
この場合、構造体は後でスコープから外れ、そもそも構造体への参照を保持しないため、(この特定のコードでは)何もできなかったため、これは実際には何もしません。
これはより理にかなっています(ただし、実際には「ベストプラクティス」ではありません)
struct foo
{
int a;
};
foo* q() { foo *f = new malloc(sizeof(foo)); f->a = 4; return f; }
int main()
{
foo i;
i.a = 5;
//sets the contents of the newly created foo
//to the contents of your i variable
(*(q())) = i;
}
これの1つの興味深いアプリケーション:
void f(const std::string& x);
std::string g() { return "<tag>"; }
...
f(g() += "</tag>");
ここで、g() +=
は一時を変更します。これは、g()の戻り値に割り当てられたヒープに、+
を収容するのに十分な予備容量がある可能性があるため、</tag>
で追加の一時を作成するよりも高速です。
それが実行されるのを見てください ideone.comでGCC/C++ 11を使用 。
さて、どのコンピューティング初心者が最適化と悪について何かを言いましたか...? ;-]。