これは、「割り当ての左オペランドとして必要な左辺値」エラーの質問のすべてを逆にしたものです。
operator []をオーバーロードするクラスがありますが、一時を返すバージョンのみです。 intを返す場合:
struct Foo
{
int operator[]( int idx ) const { return int( 0 ); }
};
Foo f;
f[1] = 5;
当然、左辺値コンパイラエラーが発生します。ただし、構造体タイプを返す場合、コンパイラ(この場合はGCC 7.2)は文句を言いません。
struct Bar {};
struct Foo
{
Bar operator[]( int idx ) const { return Bar(); }
};
Foo f;
f[1] = Bar();
Barが一時的で、特殊な演算子=がない場合、なぜこれが同じように文句を言わないのですか?別の質問ですが、これを不満にする方法はありますか?明らかにこの方法で使用した場合、これはコーディングエラーです。
これを不満にする方法はありますか?
Ref-qualifierで明示的にデフォルト設定された代入演算子を使用できます。
struct Bar {
Bar& operator=(const Bar&) & = default;
// ^
これにより、右辺値の割り当てが正しくありませんが、左辺値の割り当ては整形式のままです。
割り当て演算子を宣言すると、暗黙の移動割り当てが無効になるため、必要に応じて(デフォルトとして、適切な場合は、rvalue ref修飾子を使用して)定義も必要になる場合があることに注意してください。
Barが一時的であり、特殊な演算子=がない場合、なぜこれが同じように文句を言わないのですか?
暗黙的に生成された代入演算子は参照修飾されていないためです。
明らかにこの方法で使用した場合、これはコーディングエラーです。
右辺値の割り当ては、一般的にエラーではありません。参照のように動作すると想定されている一部の型では、右辺値の割り当ては自然です。これは、割り当てが一時オブジェクト自体ではなく、参照オブジェクトを変更するためです。
典型的な使用例は、右辺値std::tie
への割り当てです(例 cppreference から):
std::set<S> set_of_s; // S is LessThanComparable
S value{42, "Test", 3.14};
std::set<S>::iterator iter;
bool inserted;
// unpacks the return value of insert into iter and inserted
std::tie(iter, inserted) = set_of_s.insert(value);
はい、暗黙の演算子が修飾されていて、非修飾には明示的な宣言が必要な場合、参照型が標準よりも例外的であることを考えると、より良いかもしれません。しかし、それは言語のあり方ではなく、言語の変更は後方互換性のない変更です。
はい、これらのメソッドを削除してこれをコンパイルエラーにする方法があります。
Bar& operator=(const Bar&)&& =delete;
Bar& operator=(Bar&&)&& =delete;
これにより、他の演算子とコンストラクターの自動生成が無効になるので、それらをすべて定義する必要があることに注意してください。
struct Bar {
Bar()=default;
Bar(const Bar&) = default;
Bar& operator=(const Bar&)&& =delete;
Bar& operator=(Bar&&)&& =delete;
Bar& operator=(const Bar&)& =default;
Bar& operator=(Bar&&)& =default;
};