Uniform Initialization と std::initializer_list

前回の C++読書会で読んだ C++11: A cheat sheet―Alex Sinyakov に書かれていたので覚書。


さて、C++11 で追加された Uniform Initialization なのですが、次のように auto を使用した場合、{} と () では定義される型が変わってしまいます。

// C++11: A cheat sheet―Alex Sinyakov
// Uniform Initialization and std::initializer_list
//
// Don’t mix std::initializer_list with auto
auto w(n);       // int
auto x = n;      // int
auto y{n};       // std::initializer_list<int>
auto z = {n};    // std::initializer_list<int>


上記のように {} を使用した場合は initializer_list 型として定義されます。
上から3番目(y{n}) はうっかり書いてしまいそうですね。
また、initializer_list を受け取るコンストラクタが定義されている型を初期化する場合にも注意が必要です。
例えば、次のように std::vector を初期化する場合とか。

std::vector<int> v1(5);    // constructor(5)
// => {0, 0, 0, 0, 0]
std::vector<int> v2{5};    // constructor(std::initializer_list<int>{5})
// => {5}


ここら辺の仕様はちゃんと覚えておいた方がいいですね。
はまらないようにしないと。

[ソース]

#include <iostream>
#include <initializer_list>
#include <vector>
#include <algorithm>
#include <iterator>

int
main(){
    std::vector<int> v;
    
    int n = 0;
    
    auto w(n);       // int
    static_assert(std::is_same<decltype(w), int>{}, "");

    auto x = n;      // int
    static_assert(std::is_same<decltype(x), int>{}, "");

    auto y{n};       // std::initializer_list<int>
    static_assert(std::is_same<decltype(y), std::initializer_list<int>>{}, "");

    auto z = {n};    // std::initializer_list<int>
    static_assert(std::is_same<decltype(z), std::initializer_list<int>>{}, "");


    std::vector<int> v1(5);    // constructor(5)
    std::copy(std::begin(v1), std::end(v1), std::ostream_iterator<int>(std::cout, ","));
    std::cout << "\n";

    std::vector<int> v2{5};    // constructor(std::initializer_list<int>{5})
    std::copy(std::begin(v2), std::end(v2), std::ostream_iterator<int>(std::cout, ","));
    std::cout << "\n";

    return 0;
}

[出力]

0,0,0,0,0,
5,