#include <iostream>
#include <vector>
int main()
{
auto v1 = std::vector<std::size_t>(std::size_t{8});
std::cout << v1.size() << std::endl;
auto v2 = std::vector<std::size_t>{std::size_t{8}};
std::cout << v2.size() << std::endl;
}
The code outputs:
8
1
I know this is a well-known problem in C++ because of:
std::vector<std::size_t>(std::size_t{8})
calls
explicit vector(size_type count)
while
std::vector<std::size_t>{std::size_t{8}}
calls
vector(std::initializer_list<T> init, const Allocator& alloc = Allocator())
.
To my surprise:
Why does the second call not trigger a compile-time error for overload resolution ambiguity?
In another related question, a piece of similar code does trigger an ambiguity error.
Because there is no ambiguity that can cause an error. Overload resolution is explicitly different when we use list initialization. It's done intentionally in two phases.
[over.match.list]
1 When objects of non-aggregate class type T are list-initialized ([dcl.init.list]), overload resolution selects the constructor in two phases:
Initially, the candidate functions are the initializer-list constructors ([dcl.init.list]) 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.
If the initializer list has no elements and T has a default constructor, the first phase is omitted. In copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed. [ Note: This differs from other situations ([over.match.ctor], [over.match.copy]), where only converting constructors are considered for copy-initialization. This restriction only applies if this initialization is part of the final result of overload resolution. — end note ]
In the first step only std::initializer_list
constructors are considered. And we can reach the second step where other constructors are considered only if the first overload resolution failed. Obviously overload resolution does not fail to find an appropriate std::initializer_list
constructor.
The question you link to is not about ambiguity in initializing vectors. The ambiguity is in choosing a function overload. Both are viable because both accept a different vector that can be itself initialized unambiguously from the same initializer list.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With