struct STest : public boost::noncopyable {
STest(STest && test) : m_n( std::move(test.m_n) ) {}
explicit STest(int n) : m_n(n) {}
int m_n;
};
STest FuncUsingConst(int n) {
STest const a(n);
return a;
}
STest FuncWithoutConst(int n) {
STest a(n);
return a;
}
void Caller() {
// 1. compiles just fine and uses move ctor
STest s1( FuncWithoutConst(17) );
// 2. does not compile (cannot use move ctor, tries to use copy ctor)
STest s2( FuncUsingConst(17) );
}
上記の例は、Microsoft Visual C++ 2012 で実装されている C++11 で、関数の内部詳細がその戻り値の型を変更できることを示しています。今日まで、たとえば、後続の関数呼び出しにパラメーターとして渡される場合など、戻り値がどのように処理されるかを理解するためにプログラマーが知る必要があるのは、戻り値の型の宣言だけであると私は理解していました。そうではありません。
必要に応じてローカル変数を作成するのが好きconst
です。一連の思考を整理し、アルゴリズムを明確に構造化するのに役立ちます。ただし、宣言された変数を返すことに注意してくださいconst
。たとえ変数がアクセスされなくなったとしても (return
結局のところ、ステートメントが実行された)、宣言された変数const
が長い間スコープ外に出ていたとしても (パラメーター式の評価が完了している)、移動することはできません。コピーできません (コピーできない場合はコンパイルに失敗します)。
この質問は、別の質問Move Semantics & return const valuesに関連しています。違いは、後者では関数が値を返すように宣言されていることconst
です。私の例でFuncUsingConst
は、揮発性の一時を返すように宣言されています。ただし、関数本体の実装の詳細は戻り値の型に影響し、戻り値を他の関数のパラメーターとして使用できるかどうかを決定します。
この動作は標準で意図されていますか?
これはどのように有用であると見なすことができますか?
おまけの質問: 呼び出しと実装が異なる翻訳単位にある可能性がある場合、コンパイラはコンパイル時にどのように違いを知ることができますか?
編集:質問を言い換える試み。
関数の結果に、宣言された戻り値の型以外のものがある可能性はありますか? 関数の宣言が関数の戻り値の動作を決定するのに十分ではないということは、どのように受け入れられるのでしょうか? 私にはこれが FUBAR のケースのように思えますが、標準のせいにするのか、それとも Microsoft の実装のせいにするのかよくわかりません。
呼び出された関数の実装者として、すべての呼び出し元を知ることさえ期待できません。ましてや、呼び出し元のコードの小さな変更をすべて監視することはできません。一方、呼び出し元の関数の実装者として、関数の実装のスコープ内でたまたま const と宣言されている変数を、呼び出された関数が返さないことに依存することはできません。
関数宣言はコントラクトです。それは今何の価値がありますか?ここでは、意味的に同等のコンパイラの最適化については話していません。たとえば、あると便利ですが、コードの意味を変更しないコピー省略などです。copy ctor が呼び出されるかどうかによって、コードの意味が変わります (さらに、上記のように、コンパイルできない程度までコードが壊れることもあります)。私がここで議論していることのぎこちなさを理解するために、上記の「おまけの質問」を考えてみてください。