web-dev-qa-db-ja.com

クラスの関数宣言後の「デフォルト」とはどういう意味ですか?

クラスの関数宣言の隣でdefaultが使用されているのを見てきました。それは何をするためのものか?

class C {
  C(const C&) = default;
  C(C&&) = default;
  C& operator=(const C&) & = default;
  C& operator=(C&&) & = default;
  virtual ~C() { }
};
198
Paul Manta

新しいC++ 11機能 です。

これは、その関数のコンパイラー生成バージョンを使用することを意味するため、本文を指定する必要はありません。

= deleteを使用して、コンパイラーがその関数を自動的に生成するしないことを指定することもできます。

移動コンストラクターと移動代入演算子の導入により、コンストラクター、デストラクタ、および代入演算子の自動バージョンが生成されるときのルールは非常に複雑になりました。 = default= deleteを使用すると、ルールを覚える必要がないため、物事が簡単になります。何をしたいかを言うだけです。

225
Peter Alexander

これは、それぞれのコンストラクターまたは割り当て演算子のデフォルトバージョン、つまり各メンバーのコピーまたは移動アクションを実行するもののデフォルトバージョンを作成するようコンパイラーに指示する新しいC++ 0x機能です。これは、コピーコンストラクター(および同様に割り当て)とは異なり、移動コンストラクターが常にデフォルトで生成されるわけではないため(たとえば、カスタムデストラクターがある場合)、便利です。コンパイラは、毎回自分でそれを綴るよりもそれを処理します。

また、他のデフォルト以外のコンストラクターを指定した場合、デフォルトのコンストラクターは生成されないことに注意してください。それでもデフォルトのコンストラクタが必要な場合は、この構文を使用してコンパイラにコンストラクタを作成させることができます。

別のユースケースとして、コピーコンストラクターが暗黙的に生成されないいくつかの状況があります(たとえば、カスタム移動コンストラクターを提供する場合)。引き続きデフォルトバージョンが必要な場合は、この構文でリクエストできます。

詳細については、標準のセクション12.8を参照してください。

41
Kerrek SB

C++ 11の新機能です。 here を参照してください。 1つのコンストラクターを定義したが、他のコンストラクターにはデフォルトを使用したい場合に非常に役立ちます。 C++ 11より前のバージョンでは、デフォルトと同等であっても、一度コンストラクタを定義したら、すべてのコンストラクタを定義する必要がありました。

また、特定の状況では、defaultvalue初期化。 defaultを使用すると、その動作を取り戻すことができます。

21
juanchopanza

これらの回答で言及されていない別のユースケースは、コンストラクターの可視性を簡単に変更できることです。たとえば、友人クラスがコピーコンストラクタにアクセスできるようにしたいが、パブリックに利用できるようにしたくない場合があります。

11
dshin

C++ 17 N4659標準ドラフト

https://github.com/cplusplus/draft/blob/master/papers/n4659.pdf 11.4.2 "明示的にデフォルト設定された関数":

1フォームの関数定義:

attribute-specifier-seq opt decl-specifier-seq opt declarator virt-specifier-seq opt = default ;

明示的にデフォルト設定された定義と呼ばれます。明示的にデフォルト設定されている関数は

  • (1.1)—特別なメンバー関数である、

  • (1.2)—宣言された同じ関数型を持ちます(ref修飾子が異なる場合を除き、コピーコンストラクターまたはコピー割り当て演算子の場合を除き、パラメーターの型は "非定数Tへの参照"になる場合があります。メンバー関数のクラスの名前)、暗黙的に宣言されたかのように

  • (1.3)—デフォルトの引数はありません。

2削除済みとして定義されていない明示的にデフォルト設定された関数は、constexprとして暗黙的に宣言されている場合にのみconstexprとして宣言できます。関数が最初の宣言で明示的にデフォルト設定されている場合、暗黙の宣言がそうである場合、関数は暗黙的にconstexprと見なされます。

3明示的にデフォルト設定されている関数が、暗黙の宣言(18.4)と同じ例外仕様を生成しないnoexcept-specifierで宣言されている場合、

  • (3.1)—関数が最初の宣言で明示的にデフォルト設定されている場合、削除済みとして定義されます。

  • (3.2)—それ以外の場合、プログラムは不正な形式です。

4 [例:

struct S {
  constexpr S() = default;            // ill-formed: implicit S() is not constexpr
  S(int a = 0) = default;             // ill-formed: default argument
  void operator=(const S&) = default; // ill-formed: non-matching return type
  ~ S() noexcept(false) = default;    // deleted: exception specification does not match
private:
  int i;                              // OK: private copy constructor
  S(S&);
};
S::S(S&) = default;                   // OK: defines copy constructor

—終了例]

5明示的にデフォルト化された関数と暗黙的に宣言された関数は、まとめてデフォルト化関数と呼ばれ、実装はそれらの暗黙的な定義(15.1 15.4、15.8)を提供します。関数は、ユーザーが宣言し、その最初の宣言で明示的にデフォルト設定または削除されていない場合、ユーザーが提供します。ユーザーが明示的にデフォルト設定した関数(つまり、最初の宣言後に明示的にデフォルト設定)は、明示的にデフォルト設定された時点で定義されます。そのような関数が暗黙的に削除済みとして定義されている場合、プログラムの形式は正しくありません。 [注:最初の宣言後に関数をデフォルトとして宣言すると、効率的な実行と簡潔な定義を提供しながら、進化するコードベースへの安定したバイナリインターフェイスを実現できます。 —終了ノート]

6 [例:

struct trivial {
  trivial() = default;
  trivial(const trivial&) = default;
  trivial(trivial&&) = default;
  trivial& operator=(const trivial&) = default;
  trivial& operator=(trivial&&) = default;
  ~ trivial() = default;
};
struct nontrivial1 {
  nontrivial1();
};
nontrivial1::nontrivial1() = default;       // not first declaration

—終了例]

それから、もちろん、どの関数を暗黙的に宣言できるのか、いつそれが起こるのかが問題です。