- cpp29[meta cpp]
このページはC++29に採用された言語機能の変更を解説しています。
のちのC++規格でさらに変更される場合があるため関連項目を参照してください。
明示的にdefault定義する特殊メンバ関数は、暗黙に宣言されるものとシグネチャが一部異なっていてもよい。C++26までの規格ではこの許容が広く、たとえば次のような、左辺のオブジェクトが右辺値であるとする非現実的な代入演算子のdefault定義が適格だった。
struct A {
A& operator=(const A&) && = default; // C++26まで適格。C++29からコンパイルエラー
};C++29では、以下のシグネチャの代入演算子をdefault定義することが、すべて不適格となる。
- 右辺値修飾(
&&)された代入演算子(this A&&のような明示的オブジェクトパラメータの場合を含む)。C++26までは適格だった constなどのCV修飾がされた代入演算子。C++26まではdelete定義される扱いだった- パラメータがCV修飾された右辺値参照(
const A&&など)である代入演算子。C++26まではdelete定義される扱いだった
これらのシグネチャの代入演算子を、default定義ではなく自分で定義することは、引き続きできる。default定義した場合にコンパイラが生成すべき意味のある実装が存在しないため、宣言の時点で不適格とされた。
明示的にdefault化された特殊メンバ関数F1が、対応する暗黙に宣言される特殊メンバ関数F2と以下の点以外で異なる場合、プログラムは不適格となる。
F1が代入演算子である場合、&のref修飾子を持ってよい(&&は許可されない)F2が代入演算子である場合、F1は「クラスへの左辺値参照」型の明示的オブジェクトパラメータを持ってよいF1とF2の例外指定は異なってよいF2の非オブジェクトパラメータがconst C&型である場合、F1の対応するパラメータはC&型でもよく、その逆でもよいF1側をC&型とする場合に限り、最初の宣言でdefault化されていればF1はdelete定義され、そうでなければ不適格となる。これは、C(const C&) = default;のように標準的な綴りでdefault定義したクラステンプレートを、コピーコンストラクタ・コピー代入演算子がC&パラメータを持つ型でインスタンス化する場合を引き続き許容するためである
この機能に対する機能テストマクロは、有用な用途がないという判断で意図的に追加されていない。
struct A {
// ref修飾子として&を付けてdefault定義することは、引き続きできる
A& operator=(const A&) & = default;
// C++29からコンパイルエラー:右辺値修飾された代入演算子はdefault定義できない
// A& operator=(const A&) && = default;
// C++29からコンパイルエラー:const修飾された代入演算子はdefault定義できない
// A& operator=(const A&) const = default;
};
struct B {
// 右辺値修飾された代入演算子を自分で定義することは、引き続きできる
B& operator=(const B&) && { return *this; }
};
int main()
{
A a1, a2;
a1 = a2;
}右辺値修飾された代入演算子のdefault定義のような非現実的な宣言が許可されていることは、言語の理解を難しくするだけでなく、default定義の拡張を検討するほかの提案(default定義された代入演算子の戻り値型にプレースホルダー型を許可するP2952など)が、一貫性のためにこの奇妙なシグネチャ群への対応を検討しなければならないという問題を生んでいた。
当初は、これらのシグネチャをdelete定義される扱いに変更する保守的な案も併記されていたが、delete定義にはテンプレートプログラミング上の用途もないため、EWGの合意によって不適格とする案が採用された。一方で、C&パラメータのコピー代入演算子に対する既存のdelete定義の扱い(P0641で導入された、クラステンプレートの標準的なdefault定義を許容するための緩和)は維持されている。