「EffectiveModernC ++」研究ノートの第7条:オブジェクトを作成するときは、()と{}を区別するように注意してください。

オブジェクトを初期化する方法はたくさんありますが、特にC ++ 11では、少なくとも概念的には、あらゆる場面で初期化に使用できる統合初期化が新たに導入されています。現在、一般的な初期化方法はおおまかに次のとおりです。

int x(0);    //使用小括号初始化
int y = 0;   //使用等号初始化
int z{0};    //使用C++11新引入的统一初始化格式,即大括号初始化
int z1 = {0};//统一初始化格式变体,编译器对其处理完全无差别

C ++ 11では、次のようなC ++ 98では完了できない多くのタスクを処理できる統合初期化メソッドが新たに導入されました。

(1)特定のコレクションを保持するようにSTLコンテナーを初期化します。

std::vector<int> v{1,3,5};

(2)クラスの非静的メンバー変数のデフォルトの初期化値を指定します:

class Widget {

private:
    int x{0};   //可行,C++11统一初始化
    int y = 0;  //可行,使用赋值语句赋值
    int z(0);   //不可行

}

(3)等号演算子をサポートしていないstd :: atomic型オブジェクトなど、割り当てることができないオブジェクトを初期化します。()または{}を使用して以下を初期化できます。

std::atomic<int> x1{0};  //可行
std::atomic<int> x1(0);  //可行
std::atomic<int> x1 = 0; //不可行

(4)ナローイング型変換を直接禁止します。

double x = 2.3;

int sum{x};   //编译报错,会进行窄化转换检查

int sum2 = x; //编译告警,直接丢弃x的小数位

int sum3(x);  //编译告警,直接丢弃x的小数位

 

中かっこで初期化することのセキュリティと利便性は非常に優れていますが、予期しない状況もあります。2項で、中かっこで初期化された変数を受け取るためにautoを使用すると、autoが推定されると述べました。これはstd型です。 :: initializer_listであるため、関数パラメーターとして中括弧を使用する場合、そのタイプはstd :: initializer_listです。ここで問題が発生します。問題の理由は、中括弧初期化構文を使用する呼び出しステートメントをstd :: initializer_list型パラメーターを持つコンストラクターとしてコンパイラーが解釈する可能性がある限り、コンパイラーがこれを選択するためです。初期化関数としてのコンストラクタ例えば:

class Widget {
public:
   Widget(int i,bool b);
   Widget(int i,double d);
   Widget(std::initializer_list<long,double> t);

}


Widget w1(10,true);  //使用小括号,正确调用第一个构造函数

Widget w2{10,true};  //使用大括号,将调用第三个构造函数,并将其强制转化为std::initializer_list<long,double>类型,10和true被转换为long和double

上記からわかるように、初期化に中括弧が使用されている限り、コンパイラはstd :: initializer_list型パラメータでコンストラクタを使用しようとする必要がありますが、狭いパラメータを宣言すると、コンパイラは何をしますか?それに対処するには?

class Widget {
public:
   Widget(int i,bool b);
   Widget(int i,double d);
   Widget(std::initializer_list<bool,bool> t); //这里修改成bool类型来接收

}


Widget w1(10,true);  //使用小括号,还是正确调用第一个构造函数

Widget w2{10,5.0};  //使用大括号,尝试调用第三个构造函数,发现其bool类型无法容纳int和double类型,即使这样,编译器也不会调用第二个构造函数,而是直接提示编译错误

上記のことから、コンパイラーはいわゆる「可能性」を完全に完成させていることがわかります。可能性は1つだけです。中括弧が初期化されると、std :: initializer_list型パラメーターを使用してコンストラクターによってハイジャックされることはありません。 、フォームからパラメータを実際のパラメータに変換することは完全に不可能です。

class Widget {
public:
   Widget(int i,bool b);
   Widget(int i,stringd);
   Widget(std::initializer_list<std::string,std::string> t); //这里修改成string类型来接收

}


Widget w1(10,true);  //使用小括号,还是正确调用第一个构造函数

Widget w2{10,5.0};  //使用大括号,尝试调用第三个构造函数,int和double类型无论如何也转换不成string,将调用第二个构造函数

これを見て、この本の著者はあまりよく説明していなかったと思います。実際、中括弧で初期化するときのパラメーターは、std :: initializer_listのタイプと見なすことができます。コンストラクターにstd :: initializer_listのタイプがある場合、暗黙的に変換でき(狭められた場合、コンパイラーはエラーを報告します)、std :: initializer_list型パラメーターを持つコンストラクターが呼び出されます。それ以外の場合は、他の代替コンストラクターが呼び出されます。

速記

  • ブラケットの初期化は、最も幅広いコンテキストで使用でき、暗黙的なナローイング変換を防ぐことができ、最も厄介な構文解析文法の影響を受けません。
  • コンストラクターのオーバーロードの解決中、可能性がある限り、他に適切と思われるコンストラクターが存在する場合でも、中括弧の初期化はコンストラクターをstd :: initializer_list型パラメーターと一致させます。

おすすめ

転載: blog.csdn.net/Chiang2018/article/details/114108479