Because initializer_list constructors, if at all possible, take precedence over other constructors. This is to make edge cases less confusing - specifically, this particular vector constructor that you expect it to use was deemed too easily selected by accident.
Specifically, the standard says in 16.3.1.7 "Initialization by list-initialization" [over.match.list] (latest draft, N4687):
(1) 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.
So if you do std::vector<char>( i, c )
, this section does not apply at all, since it isn't list-initialization. Normal overload resolution is applied, the (size_t, char)
constructor is found, and used.
But if you do std::vector<char>{ i, c }
, this is list-initialization. The initializer list constructors are tried first, and the (initializer_list<char>)
constructor is a match (even though it involves the narrowing conversion from size_t
to char
), so it is used before the size+value constructor is ever considered.
So to answer the edited-in question: no, you can't create the vector without naming its type. But in C++17 you can use class template argument deduction and simply write return std::vector(i, c);
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…