C ++ 11で「delete
d」関数が過負荷解決に参加するのはなぜですか?
なぜこれが便利なのですか?つまり、完全に削除されるのではなく、なぜ非表示になっているのでしょうか。
C ++ 11で「delete
d」関数が過負荷解決に参加するのはなぜですか?
なぜこれが便利なのですか?つまり、完全に削除されるのではなく、なぜ非表示になっているのでしょうか。
回答:
= delete
構文の目的の半分は、人々が特定のパラメーターを使用して特定の関数を呼び出さないようにすることです。これは主に、特定のシナリオでの暗黙的な変換を防ぐためです。特定の過負荷を禁止するには、過負荷の解決に参加する必要があります。
あなたが引用する答えはあなたに完璧な例を与えます:
struct onlydouble {
onlydouble(std::intmax_t) = delete;
onlydouble(double);
};
場合はdelete
完全に機能を削除し、それはなるだろう= delete
これに構文相当します:
struct onlydouble2 {
onlydouble2(double);
};
あなたはこれを行うことができます:
onlydouble2 val(20);
これは合法的なC ++です。コンパイラーはすべてのコンストラクターを調べます。それらのどれも直接整数型を取りません。しかし、そのうちの1つは、暗黙の変換後にそれを取ることができます。だからそれを呼ぶでしょう。
onlydouble val(20);
これは合法的なC ++ではありません。コンパイラーは、delete
d個のコンストラクターを含むすべてのコンストラクターを調べます。via std::intmax_t
(整数リテラルと完全に一致します)を介して完全一致が表示されます。したがって、コンパイラはそれを選択し、delete
d関数を選択したため、すぐにエラーを発行します。
= delete
「これは存在しない」という意味ではなく、「これを禁じる」という意味です。それははるかに強力な声明です。
C ++標準で= deleteが「これは存在しない」ではなく「これを禁止する」という意味である理由を尋ねていました
「これは存在しない」と言うのに特別な文法は必要ないからです。問題の特定の「これ」を単に宣言しないことによって、これを暗黙的に取得します。「私はこれを禁じます」は、特別な文法なしでは達成できない構成を表します。そのため、「これは禁止します」という特別な文法があり、他のことはありません。
明示的な「これは存在しません」という文法を使用することで得られる唯一の機能は、後で誰かがそれを存在すると宣言するのを防ぐことです。そして、それは独自の文法を必要とするほど有用ではありません。
それ以外の場合、コピーコンストラクターが存在しないことを宣言する方法はなく、その存在によって無意味なあいまいさが生じる可能性があります。
コピーコンストラクターは特別なメンバー関数です。すべてのクラスには常にコピーコンストラクタがあります。常にコピー代入演算子、ムーブコンストラクタなどがあるのと同じように。
これらの機能は存在します。問題は、それらを呼び出すことが合法であるかどうかだけです。それが= delete
存在しないことを意味すると言おうとした場合、仕様は関数が存在しないことの意味を説明する必要があります。これは、仕様が扱う概念ではありません。
まだ宣言/定義されていない関数を呼び出そうとすると、コンパイラはエラーになります。ただし、「関数が存在しません」エラーではなく、未定義の識別子が原因でエラーが発生します(コンパイラがそのように報告した場合でも)。さまざまなコンストラクターはすべてオーバーロード解決によって呼び出されるため、それらの「存在」はその点で処理されます。
いずれの場合も、識別子を介して宣言された関数、またはコンストラクタ/デストラクタ(識別子を介して宣言された、型識別子のみ)があります。演算子のオーバーロードは、識別子をシンタックスシュガーの背後に隠しますが、それはまだ存在しています。
C ++仕様では、「存在しない関数」の概念を処理できません。過負荷の不一致を処理できます。過負荷のあいまいさを処理できます。しかし、そこに何がないのかはわかりません。したがって= delete
、あまり有用ではない「この行を書いたことがないふりをする」よりも、はるかに有用な「これを失敗と呼ぶ試み」の観点から定義されます。
そしてもう一度、最初の部分を読み直してください。あなたはそれを行うことができないと、「機能が存在しません。」これがそのように定義されているもう1つの理由です。= delete
構文の主なユースケースの1つは、ユーザーに特定のパラメータータイプの使用、明示的なキャストなどを強制できるようにするためです。基本的に、暗黙の型変換を阻止します。
あなたの提案はそれをしません。
= delete
「このメンバーは存在しません」という意味で、過負荷の解決に参加できなかったことを意味します。
= delete
「このメンバーが存在しない」という意味の場合、最初に投稿した例では、人々がonlydouble
のコンストラクターに整数を渡すのを防ぐことはできません。、onlydouble
削除されるオーバーロードは存在しないため。オーバーロードの解決には関与しないため、整数の受け渡しを妨げることはありません。これは= delete
構文のポイントの半分です。「この関数に暗黙的にXを渡すことはできません」と言うことができます。
=delete
はまったく必要なのですか?結局のところ、まったく同じこと、つまりコピーコンストラクタ/代入をプライベートとして宣言することで、「コピー不可」と言うことができます。また、プライベートなものを宣言しても、呼び出し不能になるわけではないことに注意してください。クラス内のコードは引き続きそれを呼び出すことができます。したがって、と同じではありません= delete
。いいえ、= delete
構文を使用すると、以前は非常に不便で不可解だったことが、はるかに明白で合理的な方法で実行できます。
C ++ワーキングドラフト2012-11-02は、このルールの背後にある理論的根拠を提供していません。いくつかの例だけです。
8.4.3削除された定義[dcl.fct.def.delete]
...
3 [例:デフォルト以外の初期化と非整数初期化を強制することができます。
struct onlydouble {
onlydouble() = delete; // OK, but redundant
onlydouble(std::intmax_t) = delete;
onlydouble(double);
};
—終了例]
[例:特定の新しい式でクラスが使用されないようにするには、そのクラスに対して新しいユーザー宣言演算子の定義を削除します。
struct sometype {
void *operator new(std::size_t) = delete;
void *operator new[](std::size_t) = delete;
};
sometype *p = new sometype; // error, deleted class operator new
sometype *q = new sometype[3]; // error, deleted class operator new[]
—終了例]
[例:コピーコンストラクターとコピー代入演算子の削除された定義を使用し、次にムーブコンストラクターとムーブ代入演算子のデフォルト定義を提供することにより、クラスをコピー不可、つまり移動専用にすることができます。
struct moveonly {
moveonly() = default;
moveonly(const moveonly&) = delete;
moveonly(moveonly&&) = default;
moveonly& operator=(const moveonly&) = delete;
moveonly& operator=(moveonly&&) = default;
~moveonly() = default;
};
moveonly *p;
moveonly q(*p); // error, deleted copy constructor
—終了例]