Foo f = Foo();// 'Foo::Foo(Foo)' の呼び出しに一致する関数がありません … あれ?

StackOverflow https://stackoverflow.com/questions/2776313

  •  03-10-2019
  •  | 
  •  

質問

class Foo
{
public:
    explicit Foo() {}
    explicit Foo(Foo&) {}
};

Foo d = Foo();

エラー:「Foo::Foo(Foo)」の呼び出しに一致する関数がありません

変えてみた Foo(Foo&)Foo(Foo) エラーが示すように、私の知る限り、これは有効なコンストラクターではありません。そして、確かに次の結果が得られます。

エラー:無効なコンストラクター。おそらく「Foo (const Foo&)」という意味でしょう

何が与えますか?これを解決するにはどうすればよいですか?(ちなみにこれはGCCにあります)

役に立ちましたか?

解決

コピー コンストラクターには疑わしいものが 2 つあります。

まず、コピーコンストラクターを明示的にしたので (これは疑わしいことですが)、(理論的には) 次のことを行う必要があります。

Foo d( (Foo()) );

次に、コピー コンストラクターは、 const 参照。つまり、一時的な参照では使用できません。 Foo.

個人的には削除したいです explicit コピーコンストラクターから取得して、 const できれば参考に。

注意してください。 explicit デフォルトのコンストラクターでは効果がありません。[*] explicit 単一のパラメータで呼び出すことができるコンストラクタにのみ影響します。これにより、それらが暗黙的な変換に使用されるのを防ぎます。ゼロまたは 2 つ以上のパラメーターのみを取るコンストラクターの場合、効果はありません。

[注記:次のような違いがある可能性があります。

Foo d;

そして

Foo d = Foo();

ただし、この場合はユーザーが宣言したデフォルトのコンストラクターがあるため、これは適用されません。]

編集:[*] これを再確認したところ、12.3.1 [class.conv.ctor] にはデフォルトのコンストラクターを作成できると記載されています explicit. 。この場合、コンストラクターは実行に使用されます。 デフォルトの初期化 または 値の初期化. 。正直に言うと、ユーザーが宣言したコンストラクターがある場合、それは非POD型であり、非POD型のローカルオブジェクトであっても、初期化子がなければデフォルトで初期化されるため、この値の意味がわかりません。この条項で述べていることは、 explicit デフォルトのコンストラクター。おそらく誰かがそれが違いを生む特殊なケースを指摘してくれるかもしれないが、今のところ私にはどのような効果があるのか​​分からない explicit デフォルトのコンストラクターにあります。

他のヒント

これらのコンストラクターのいずれかを明示的であるとマークしたくありません。コンパイラは、それらの両方、特にコピーコンストラクターを暗黙的に使用する必要があります。それらを明示的にマークすることで何を達成しようとしていますか?

まず、デフォルトのコンストラクターもコピーコンストラクターも explicit. 。コンストラクターを作るだけです explicit そのタイプからの暗黙の変換を防ぐために、他のタイプの単一の引数が必要な場合。コピーコンストラクターはクラス自体への参照を取得するため、望ましくない変換の危険はありません。

第二に、コピーコンストラクターが const 参照。

第3、 Foo f; クラスFOOのデフォルトで構成されたオブジェクトを持つ正しい方法です。ご了承ください Foo f(); コンパイラがそれを機能の宣言として解釈するので、間違っています f() クラスのオブジェクトを返します Foo.

第四に、独自のコピーコンストラクターを書いた場合は、割り当てオペレーターも書く必要があります。


class Foo
{
  Foo() {} // no need to make explicit.  Nothing to convert from.

  Foo(const &Foo f) {} // again, nothing wrong with conversion from Foo to Foo

  explicit Foo(int a) {}  // need explicit to prevent accidental passing of an int
                          // to a function that takes Foo as an argument
};

明示なしで試してみませんか?私はそう思う:

Foo foo = Foo()

暗黙のコピーを作成するため、明示的なコピーコンストラクターはトリガーされません。

編集:

これは答えの半分に過ぎません。 Constが必要な理由については、Charles BaileyまたはAnblebensの投稿を参照してください。

コピーコンストラクターはそうすべきではありません 明示的 (これは、ここでも、価値を通過したり返還したりするときなど、他の多くの完全に合理的なコンテキストでは不可能になります)。

次に、議論を取る必要があります const 参照してください。それ以外の場合は、タイムリーにバインドできないためです。

Foo f = Foo();
        ^^^^^
          |
          --- this is a temporary that cannot be passed to a function
              that accepts a non-const reference

さらに、デフォルトのコンストラクターを作成する理由はありません 明示的: :このキーワードは、正確に1つの引数で呼び出すことができるコンストラクター(コピーコンストラクター以外)に対してのみ理にかなっています。その場合、そのコンストラクターを介して他のタイプのfooへの暗黙的な変換を防ぎます。たとえば、コンストラクターがandを取る場合 int そうだった 明示的, 、このような状況はコンパイルされません。

Foo f;
f = 1;  //assuming no operator= overload for (types convertible from) int
        //this implicitly performs f = Foo(1);

Foo g = 10;

void x(Foo);
x(20);

概して:

class Foo
{
public:
    Foo();
    Foo(const Foo&);
    //...
};

Foo x = Foo();

さらに、これらのコンストラクターがどちらも何もすることを意図していない場合、それらをまったく定義する必要はありません - コンパイラはそれらを自動的に提供します(ただし、他のコンストラクターを定義する場合、デフォルトのコンストラクターは自動的に生成されません)。

Foo d = Foo();

あるべきです

Foo d;

最初の行はFOOインスタンスを作成し、それをDにコピーします。

あなたの問題はインスタンスにあります。必要はありません Foo d = Foo(); デフォルトのコンストラクター用。

クラスを同じように保ちますが、インスタンス化のためにこれを試してください。

Foo d;

実際、あなたも必要ありません Foo d = Foo(arguments); パラメーターで構築するため。それは次のようになるはずです:

Foo d(arguments);

コンパイラはあなたに言っています...これを使用してください:

Foo(const Foo&) {}

2つの方法のいずれかで問題を治すことができます。 1つ(すでにRandolphoが提案している)は、コピーCTORを使用して排除することです。もう1つは、適切なコピーCTORを書くことです。

Foo (Foo const &) {}

あなたは一般的に両方をしたいです。

編集:それを見ると、私の最後のコメントは簡単に構築できます。かなりの数のクラスがします いいえ コピーctorが必要ですが もしも コピーCTORが必要です。通常、上記のフォームを使用する必要があります(明示的ではなく、パラメーターとしてconst Referenceを使用します)。

class Foo
{
public:
    explicit Foo() {}
    explicit Foo(const Foo&) {}
};

Foo d = Foo()
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top