44

最近、明示的なデフォルトコンストラクターを必要とするC++0xのクラスに気づきました。ただし、デフォルトのコンストラクターを暗黙的に呼び出すことができるシナリオを思い付くことができません。それはかなり無意味な指定子のようです。Class c;多分それは賛成することを許さないだろうと思っClass c = Class();たが、そうではないようだ。

C ++ 0x FCDからのいくつかの関連する引用は、ナビゲートしやすいためです[同じ場所にない場合でも、同様のテキストがC++03に存在します]

12.3.1.3 [class.conv.ctor]

デフォルトのコンストラクターは、明示的なコンストラクターの場合があります。このようなコンストラクターは、デフォルトの初期化または値の初期化(8.5)を実行するために使用されます。

明示的なデフォルトコンストラクターの例を引き続き提供しますが、上記で提供した例を模倣しているだけです。

8.5.6 [decl.init]

デフォルトで-タイプTのオブジェクトを初期化するということは、次のことを意味します。

— Tが(おそらくcv修飾された)クラスタイプの場合(第9節)、Tのデフォルトコンストラクターが呼び出されます(Tにアクセス可能なデフォルトコンストラクターがない場合、初期化は不正な形式になります)。

8.5.7 [decl.init]

タイプTのオブジェクトを値初期化するということは、次のことを意味します。

— Tがユーザー提供のコンストラクター(12.1)を持つ(おそらくcv修飾された)クラスタイプ(条項9)の場合、Tのデフォルトコンストラクターが呼び出されます(Tにアクセス可能なデフォルトコンストラクターがない場合、初期化は不正な形式になります) );

どちらの場合も、標準ではデフォルトのコンストラクターが呼び出される必要があります。しかし、それは、デフォルトのコンストラクターが非明示的である場合に起こることです。完全を期すために:

8.5.11 [decl.init]

オブジェクトに初期化子が指定されていない場合、オブジェクトはデフォルトで初期化されます。

私の知る限り、これはデータなしからの変換を残すだけです。これは意味がありません。私が思いつくことができる最高のものは次のとおりです。

void function(Class c);
int main() {
  function(); //implicitly convert from no parameter to a single parameter
}

しかし、明らかにそれはC++がデフォルトの引数を処理する方法ではありません。他に何がexplicit Class();違う振る舞いをするのでしょうClass();か?

この質問を生成した特定の例は、std::function[20.8.14.2func.wrap.func]でした。いくつかの変換コンストラクターが必要であり、いずれも明示的にマークされていませんが、デフォルトのコンストラクターはです。

4

2 に答える 2

35

これは、明示的なデフォルト コンストラクターを宣言します。

struct A {
  explicit A(int a1 = 0);
};

A a = 0; /* not allowed */
A b; /* allowed */
A c(0); /* allowed */

次の例のようにパラメータがない場合、explicitは冗長です。

struct A {
  /* explicit is redundant. */
  explicit A();
};

一部の C++0x ドラフト (n3035 だったと思います) では、次のような違いがありました。

A a = {}; /* error! */
A b{}; /* alright */

void function(A a);
void f() { function({}); /* error! */ }

しかし、FCD では、 3 つのケースすべてがそれぞれのオブジェクトを値で初期化するという点で、これを変更しました(ただし、この特定の理由を念頭に置いていなかったのではないかと思います) 。値の初期化はオーバーロード解決のダンスを行わないため、明示的なコンストラクターで失敗することはありません。

于 2010-05-14T19:24:15.807 に答える
5

特に明記されていない限り、以下のすべての標準参照はN4659 を​​指します: 2017 年 3 月の Kona 作業ドラフト/C++17 DIS


(この回答は、特にパラメーターを持たない明示的なデフォルトコンストラクターに焦点を当てています)


ケース #1 [ C++11 から C++20 ]:{}非集計の空のコピー リスト初期化により、明示的なデフォルト コンストラクターの使用が禁止される

[over.match.list]/1 [emphase mine]によって管理されるように:

T[dcl.init.list] で、このセクションの規則に従ってオーバーロード解決が実行されるように指定されているように、非集合クラス型のオブジェクトがリスト初期化されている場合、オーバーロード解決は 2 つのフェーズでコンストラクターを選択します。

  • (1.1)最初は、候補関数はクラスの初期化子リスト コンストラクタ ([dcl.init.list]) でTあり、引数リストは単一の引数としての初期化子リストで構成されます。
  • (1.2)実行可能な初期化子リスト コンストラクターが見つからない場合、オーバーロードの解決が再度実行されます。ここで、候補関数はクラスのすべてのコンストラクターでTあり、引数リストは初期化子リストの要素で構成されます。

初期化子リストに要素がなくT、デフォルトのコンストラクターがある場合、最初のフェーズは省略されます。copy-list-initialization では、explicitコンストラクターが選択されている場合、初期化の形式が正しくありません。[<em>注: これは、コンストラクターの変換のみがコピー初期化の対象と見なされる他の状況 ([over.match.ctor]、[over.match.copy]) とは異なります。この制限は、この初期化がオーバーロード解決の最終結果の一部である場合にのみ適用されます。— <em>終わりのメモ]

非集合体の空の波括弧 初期化リストによるコピーリスト初期化は、明示的なデフォルト コンストラクターの使用を禁止します。{}例えば:

struct Foo {
    virtual void notAnAggregate() const {};
    explicit Foo() {}
};

void foo(Foo) {}

int main() {
    Foo f1{};    // OK: direct-list-initialization

    // Error: converting to 'Foo' from initializer
    // list would use explicit constructor 'Foo::Foo()'
    Foo f2 = {};
    foo({});
}

上記の標準的な引用は C++17 を参照していますが、これは C++11、C++14、および C++20 にも同様に適用されます。


ケース #2 [ C++17 のみexplicit]:集合体ではないとマークされているユーザー宣言コンストラクターを持つクラス型

[dcl.init.aggr]/1が追加され、C++14 と C++17 の間でいくつか更新されました。主に、いくつかの制限付きで集約が基本クラスからパブリックに派生できるようにすることですが、集約のexplicitコンストラクターを禁止することもできます [強調鉱山]:

集約は、配列またはクラスです。

  • (1.1)ユーザー提供explicit、、または継承されたコンストラクター([class.ctor]) はありません。
  • (1.2) プライベートまたは保護された非静的データ メンバーがない ([class.access] 節)。
  • (1.3) 仮想機能なし、および
  • (1.4) 仮想、プライベート、または保護された基本クラス ([class.mi]) はありません。

C++20 用に実装されたP1008R1 (ユーザーが宣言したコンストラクターを使用した集計を禁止する)の時点で、集計のコンストラクターを宣言することはできなくなりました。ただし、C++17 だけでは、ユーザーが宣言した (ただしユーザーが提供したものではない) コンストラクターが明示的にマークされているかどうかによって、クラスの型が集約であるかどうかが決まるという独特の規則がありました。たとえば、クラスの種類

struct Foo {
    Foo() = default;
};

struct Bar {
    explicit Bar() = default;
};

次のように、C++11 から C++20 で集計された/集計されていない:

  • C++11: Foo&Barは両方とも集計です
  • C++14: Foo&Barは両方とも集合体です
  • C++17:Foo集計のみです (コンストラクターBarを持ちます)explicit
  • C++20: 集合体ではありません(FooどちらBarもユーザー宣言のコンストラクターを持ちます)
于 2020-09-23T18:02:30.230 に答える