web-dev-qa-db-ja.com

デフォルトのコンストラクターと2つ以上の(デフォルト以外の)パラメーターを持つコンストラクターに明示的に許可されるのはなぜですか?

1つの(デフォルト以外の)パラメーターを持つコンストラクターは、そのパラメーター型からクラス型に変換する暗黙のコンバーターのように機能することを理解しています。ただし、explicitを使用して、パラメーターのないコンストラクター(デフォルトのコンストラクター)または2つ以上のパラメーターを持つコンストラクター(デフォルト以外)を修飾できます。

これらのコンストラクターで明示的に許可されるのはなぜですか?これが何らかの暗黙の変換を防ぐのに役立つ例はありますか?

32
Ashwin Nanjappa

確かに一つの理由はそれが傷つかないからです。

それが必要な理由の1つは、最初のパラメーターにデフォルトの引数がある場合です。コンストラクターはデフォルトのコンストラクターになりますが、変換コンストラクターとして使用できます。

struct A {
  explicit A(int = 0); // added it to a default constructor
};

C++ 0xは、マルチパラメーターコンストラクターに実際に使用します。 C++ 0xでは、初期化子リストを使用してクラスオブジェクトを初期化できます。哲学は

  • = { ... }を使用する場合は、オブジェクトの抽象値を概念的に表し、型に変換したい一種の「複合値」でオブジェクトを初期化します。

  • { ... }初期化子を使用する場合は、オブジェクトのコンストラクターを直接呼び出します。必ずしも変換を指定する必要はありません。

この例を考えてみましょう

struct String {
    // this is a non-converting constructor
    explicit String(int initialLength, int capacity);
};

struct Address {
    // converting constructor
    Address(string name, string street, string city);
};

String s = { 10, 15 }; // error!
String s1{10, 15}; // fine

Address a = { "litb", "nerdsway", "frankfurt" }; // fine

このように、C++ 0xは、他のコンストラクターで明示的に許可するというC++ 03の決定は、まったく悪い考えではなかったことを示しています。

おそらくそれはメンテナンスをサポートすることでした。複数引数のコンストラクターでexplicitを使用することにより、引数にデフォルトを追加するときに誤って暗黙の変換を導入することを回避できます。私はそれを信じていませんが;代わりに、C++では、言語定義を以前よりも複雑にしないために、多くのことが許可されているだけだと思います。

おそらく最も悪名高いケースは、非staticローカル変数への参照を返すことです。他に影響を与えることなくすべての「無意味な」ものを除外するには、追加の複雑なルールが必要になります。したがって、許可されているだけで、その参照をseするとUBが生成されます。

または、コンストラクターの場合、署名が異なる限り、デフォルトのコンストラクターをいくつでも定義できますが、コンストラクターが複数ある場合は、デフォルトでそれらのいずれかを呼び出すのはかなり困難です。 :-)

より良い質問は、おそらく、変換演算子でexplicitも許可されないのはなぜですか?

そうですね、C++ 0xではそうなるでしょう。ですから、そうしない理由はありませんでした。変換演算子でexplicitを許可しない実際の理由は、見落としと同じくらい乱暴であるか、そもそもexplicitを採用するのに苦労している、または委員会の時間の単純な優先順位付けなどです。

乾杯&hth。、

それはおそらく単なる便利です。 dis-許可する理由はありません。それでは、なぜコードジェネレーターなどの生活を困難にするのでしょうか。チェックした場合、コード生成ルーチンには、生成されるコンストラクターに含まれるパラメーターの数を確認する追加のステップが必要になります。

varioussources によると、1つの引数だけで呼び出すことができないコンストラクターに適用した場合はまったく効果がありません。

7
Adrian Petrescu

High Integrity C++ Coding Standardによると、すべてのsinlgeパラメーターコンストラクターをexplicit型変換での偶発的な使用を回避するため。複数引数のコンストラクターの場合、複数のパラメーターを受け入れるコンストラクターがあり、それぞれにデフォルト値があり、コンストラクターをある種のデフォルトコンストラクターと変換コンストラクターに変換するとします。

class C { 
    public: 
    C( const C& );   // ok copy 
    constructor C(); // ok default constructor 
    C( int, int ); // ok more than one non-default argument 

    explicit C( int ); // prefer 
    C( double ); // avoid 
    C( float f, int i=0 ); // avoid, implicit conversion constructor 
    C( int i=0, float f=0.0 ); // avoid, default constructor, but 
                               // also a conversion constructor 
}; 
void bar( C const & ); 
void foo() 
{ 
    bar( 10 );  // compile error must be 'bar( C( 10 ) )' 
    bar( 0.0 ); // implicit conversion to C 
}
5
ArBR