11

重複の可能性:
C++11 で削除された関数がオーバーロードの解決に参加するのはなぜですか?

次の C++11 コードについて 2 つの質問があります。

#include <iostream>

using namespace std;

struct A {
  A()  { cout << "Default c-tor" << endl; }
  A(const A&)  { cout << "Copy c-tor" << endl; }
  A(A&&) = delete;
};

A f()
{
 A a;
 return a;
}

int main()
{
  A b = f();
  return 0;
}

gcc と clang で次のコンパイル エラーが発生します。

gcc-4.7.2 (g++ --std=c++11 main.cpp):

main.cpp: In function ‘A f()’:
main.cpp:16:9: error: use of deleted function ‘A::A(A&&)’
main.cpp:8:2: error: declared here
main.cpp: In function ‘int main()’:
main.cpp:21:10: error: use of deleted function ‘A::A(A&&)’
main.cpp:8:2: error: declared here

clang-3.0 (clang++ --std=c++11 main.cpp):

main.cpp:19:4: error: call to deleted constructor of 'A'
        A b = f();
          ^   ~~~
main.cpp:8:2: note: function has been explicitly marked deleted here
        A(A&&) = delete;
        ^
1 error generated.
  • 移動コンストラクターが明示的に削除されている場合、コンパイラーはコピー コンストラクターを使用すべきではありませんか?
  • 「非可動」タイプの用途を知っている人はいますか?

前もって感謝します。

4

4 に答える 4

6
A(A&&) = delete;

それを as として宣言および定義してdeleteも、まだ宣言されており、完全に存在しないわけではありません。むしろ、それは空で非公開であると宣言することに似ています(ただし同一ではありません)。そのようです:

private: 
  A(A&&){}

実際、それは、= delete利用可能になる前に他のオペレーターに時々使用されたトリックでした. 繰り返しますが、ルックアップの意味では存在しますが、それを呼び出すことは決して許可されておらず、C++ では (ほとんどまたはすべての場合で) オーバーロードの解決、名前のルックアップなど、他のすべての後に呼び出し許可が行われます。

標準は実際に言う(8.4.3)

削除された関数は暗黙的にインライン化されます。

そして、削除された関数は名前の検索に参加してはならないという注意書きがあります (私が見つけたものです)。

また、8.4.3から

宣言する以外に、削除された関数を暗黙的または明示的に参照するプログラムは、形式が正しくありません。[ 注: これには、暗黙的または明示的に関数を呼び出すこと、および関数へのポインターまたはメンバーへのポインターを形成することが含まれます。潜在的に評価されない式の参照にも適用されます。

于 2012-12-29T20:21:32.300 に答える
2

これはちょっとした調査作業ですが、ムーブ コンストラクターを宣言すると、ムーブ コンストラクターを考慮する必要があることが示されると思います。次に d を取得deleteすると、移動コンストラクターがあれば移動できる場所にオブジェクトを移動できることを意味します。移動ではなくコピーされるオブジェクトが必要な場合は、コピー コンストラクターを宣言するだけで、移動コンストラクターについては言及しません。

上記を明示的に述べている標準のステートメントをまだ見つけていませんが、上記のステートメントの一部をバックアップする 12.8 [class.copy] パラグラフ 9 に注記があります。

[ 注: ムーブ コンストラクターが暗黙的に宣言されていないか、明示的に提供されていない場合、そうでなければムーブ コンストラクターを呼び出す式は、代わりにコピー コンストラクターを呼び出すことができます。—終わりのメモ]

于 2012-12-29T20:21:45.533 に答える
2

ムーブ コンストラクターを削除しても、名前検索で見つかった一連の関数からは削除されません。通常、コードでムーブ コンストラクターを使用すると、見つかったにもかかわらず削除されているため、エラーが発生します。

コードには 2 つの移動があります。1つ目は、return aコピーの省略が可能で、コピーされるオブジェクトが左辺値(aここでは )で指定されている場合、それは移動として扱われるためです。2 番目は割り当てA b = f()にあります。これは、 af()がまだ参照にバインドされていない一時的なものを提供しているためです。

削除されたムーブ コンストラクターではなくコピー コンストラクターを見つけたい場合は、削除された定義を削除する必要があります。

于 2012-12-29T20:23:53.637 に答える
1

C++ワーキングドラフト2012-11-02から

8.4.3削除された定義[dcl.fct.def.delete]
...
2削除された関数を、宣言する以外に暗黙的または明示的に参照するプログラムは、形式が正しくありません。[:これには、関数を暗黙的または明示的に呼び出し、関数へのポインターまたはメンバーへのポインターを形成することが含まれます。これは、潜在的に評価されていない式の参照にも適用されます。関数がオーバーロードされている場合、その関数がオーバーロード解決によって選択されている場合にのみ参照されます。— end note]
...
4削除された関数は暗黙的にインラインです。

削除されたmoveコンストラクターが参照されているため、プログラムの形式が正しくありません。

移動不可能なタイプの「使用法」は、移動を防止し、ローカルオブジェクトを返さないようにすることです。私自身はそのような使い方を見たことがなく、これが理にかなっているかどうかはわかりませんが、YMMVです。

于 2012-12-29T20:47:11.587 に答える