波カッコ初期化のススメ

このエントリは、C++11 Advent Calendar 2011の参加記事です。


今回は、C++11の統一初期化記法(Uniform Initialization)を使用したスタイル改善を紹介します。


統一初期化記法とは
まず統一初期化記法というのは、コンストラクタの呼び出しを、関数呼び出しで使用する丸カッコだけでなく、Cからあった集成体初期化の波カッコも使えるようにしよう、というものです。

struct X {
    X(int a, double b, const std::string& c) {}
};

X x1(1, 3.14, "hello"); // これまでの初期化構文
X x2{1, 3.13, "hello"}; // C++11で追加された初期化構文


初期化子リストとの統一
C++11では、ユーザー定義型でも配列の初期化構文を使えるようにするためにinitializer listの機能が入ったので、初期化は波カッコの構文で統一して扱うことができるようになりました。

template <class T, class Allocator=std::allocator<T>>
class vector {
public:
    vector(initializer_list<T>);
};

...

std::vector<int> v{1, 2, 3}; // コンテナの初期化も波カッコ


配列メンバ変数の初期化
波カッコによる初期化は、メンバ変数の配列をコンストラクタで初期化するために使用することもできます。
これはC++03ではできませんでした。

#include <iostream>
#include <vector>

struct X {
    int ar[3];

    X() : ar{1, 2, 3} {} // 配列メンバ変数を初期化
};

int main()
{
    X x;

    for (int a : x.ar) {
        std::cout << a << std::endl;
    }
}
1
2
3


デフォルトコンストラクタ呼び出しの曖昧さを解消
変数宣言の際にデフォルトコンストラクタを丸カッコで呼び出すと、コンパイラがそれを関数宣言と認識してしまうという問題があります。

struct X {};

int main()
{
    X x();
}

これは環境によってはコンパイルエラーまたは警告が発生します。VC10の場合は以下のようになります:

warning C4930: 'X x(void)': プロトタイプされている関数が呼び出されませんでした (変数の定義が意図されていますか?)

統一初期化を使用すれば、この曖昧さを解消し、初期化の意図であることをコンパイラに伝えることができます。

struct X {};

int main()
{
    X x{}; // 統一初期化なら関数宣言と曖昧にならない
}


まとめ
さらっとまとめてしまいます。
C++11で導入された統一初期化記法(Uniform Initialization)の概要と、それによってスタイル改善できるケースをいくつか紹介しました。


統一初期化は他にも、テンプレートメタプログラミングにおいて、「::value」を書かずに済ませることに応用する方法も発見されています。

::valueを短くする - C++でゲームプログラミング


C++11時代のコーディングスタイルとして、統一初期化を導入してみてはいかがでしょうか。
というところで締めたいと思います。


C++11 Advent Calendar 2011、22日目のid:nagoya313さんに続きます。