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 ifX
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 toM
's corresponding assignment operator, results in an ambiguity or a function that is deleted or inaccessible from the defaulted assignment operator, or- (snip)
関連URL