yohhoyの日記

技術的メモをしていきたい日記

代入演算子のdefault指定とconstメンバ

C++11で導入された “関数への明示的default指定” に関するメモ。あるクラスがconstメンバ変数を含むとき、代入演算子(operator=)をdefault指定したときの振る舞いについて。

要約

  • コンストラクタ/代入演算子などへdefault指定(=default)は、必ずしも “実装を定義する” を意味しない。
  • default指定は “暗黙的に行われるコンストラクタ/代入演算子の自動生成” をコンパイラに明示する。このルールに従った結果、コンストラクタ/代入演算子が定義されない(=delete指定相当)こともある。

明示的にdefault指定された演算代入子では、一定の条件を満たすとき「代入演算子はdelete指定された」とみなす。このため、下記コードのクラスX宣言は正常にコンパイルできる。

struct X {
  const int m_ = 42;  // constメンバ
  X& operator=(const X&) = default;  // ?
};

ここではクラスXのコピー代入演算子を呼び出したとき、初めてコンパイルエラーとなる。

X x1, x2;
x2 = x1;  // NG: deletedな関数を使っている

gcc 4.7.2でのエラー出力例:

error: use of deleted function `X& X::operator=(const X&)'
note: `X& X::operator=(const X&)' is implicitly deleted because the default definition would be ill-formed:
error: non-static const member `const int X::m_', can't use default assignment operator

前述のようにコピー/ムーブ代入演算子がdelete指定されたと扱われるのは、クラスが “参照型のメンバ変数” または “非クラス型のconstメンバ変数” を含む、もしくは “クラス型メンバ変数のコピー/ムーブ代入演算子を呼び出せない” ときなど(詳細は12.8/p23参照)。N3337 8.4.2/p4, 12.8/p23より一部引用。

4 Explicitly-defaulted functions and implicitly-declared functions are collectively called defaulted functions, and the implementation shall provide implicit definitions for them (12.1 12.4, 12.8), which might mean defining them as deleted. (snip)

23 A defaulted copy/move assignment operator for class X is defined as deleted if X has:

  • (snip)
  • a non-static data member of const non-class type (or array thereof), or
  • a non-static data member of reference type, or
  • a non-static data member of class type M (or array thereof) that cannot be copied/moved because overload resolution (13.3), as applied to M's corresponding assignment operator, results in an ambiguity or a function that is deleted or inaccessible from the defaulted assignment operator, or
  • (snip)

関連URL