C++1z(C++17)標準ライブラリのシーケンスコンテナ(std::vector
など)にはクラステンプレート引数推論 推論ガイド(deduction guide) が追加されたが、イテレータ・ペアによるリスト初期化(list initialization)では意図しない型推論が行われる。かなり罠っぽい挙動。
// C++1z(C++17) #include <vector> std::vector v0{ 1, 2, 3, 4 }; // vector<int> に推論される // コンストラクタvector(intializer_list<int>)を選択 // v0 = 4要素[1, 2, 3, 4] std::vector v1( v0.begin(), v0.end() ); // 後述deduction guideによって // T = iterator_traits<vector<int>::iterator>::value_type // つまり vector<int> に推論される // コンストラクタvector(InputIterator, InputIterator)を選択 // v1 = 4要素[1, 2, 3, 4] std::vector v2{ v0.begin(), v0.end() }; // ★ // vector<vector<int>::iterator> に推論される // コンストラクタvector(intializer_list<vector<int>::iterator>)を選択 // v2 = 2要素[v0.begin(), v0.end()] std::vector<int> v3{ v0.begin(), v0.end() }; // (テンプレートパラメータ明示済みのため型推論は不要) // コンストラクタvector(InputIterator, InputIterator)を選択 // v3 = 4要素[1, 2, 3, 4]
std::vector<T>
クラステンプレートが提供する推論ガイド*1は次の通り。2個のイテレータ引数(InputIterator
型)からコンテナ要素型Tを導く推論ガイドであり、std::deque
, std::forward_list
, std::list
に対しても同じ目的の推論ガイドがそれぞれ提供される。
// <vector>ヘッダ namespace std { template<class InputIterator> vector(InputIterator, InputIterator) -> vector<typename iterator_traits<InputIterator>::value_type>; }
一方で、std::vector<T>
をはじめとするシーケンスコンテナは、単一のstd::initializer_list<T>
型をとるコンストラクタ*2を提供する。これによって変数v0
のような統一初期化記法が可能となっているが、「std::initializer_list<T>
コンストラクタは他コンストラクタよりも優先される」オーバーロード規則によって変数v2
のような(プログラマの意図に反するであろう)型推論が行われる。*3
N4659(C++1z DIS) 16.3.1.7/p1, 16.3.1.8/p2より一部引用。
When objects of non-aggregate class type
T
are list-initialized such that 11.6.4 specifies that overload resolution is performed according to the rules in this section, overload resolution selects the constructor in two phases:
- Initially, the candidate functions are the initializer-list constructors (11.6.4) of the class
T
and the argument list consists of the initializer list as a single argument.- If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class
T
and the argument list consists of the elements of the initializer list.(snip)
Initialization and overload resolution are performed as described in 11.6 and 16.3.1.3, 16.3.1.4, or 16.3.1.7 (as appropriate for the type of initialization performed) for an object of a hypothetical class type, where the selected functions and function templates are considered to be the constructors of that class type for the purpose of forming an overload set, and the initializer is provided by the context in which class template argument deduction was performed. (snip)
関連URL