为什么在调用不明确的ctor时没有编译时错误?
Why is no compile-time error when calling an ambiguous ctor?
#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;
}
代码输出:
8
1
我知道这是 C++ 中的一个众所周知的问题,因为:
std::vector<std::size_t>(std::size_t{8})
调用
explicit vector(size_type count)
而
std::vector<std::size_t>{std::size_t{8}}
调用
vector(std::initializer_list<T> init, const Allocator& alloc = Allocator())
.
令我惊讶的是:
为什么第二次调用没有触发重载解析歧义的编译时错误?
,一段类似的代码确实会引发歧义错误。
因为不存在会导致错误的歧义。当我们使用列表初始化时,重载解决方案明显不同。这是有意分两个阶段完成的。
[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 ]
第一步只考虑 std::initializer_list
个构造函数。我们可以到达第二步,只有在第一次重载决议失败时才考虑其他构造函数。显然重载决议不会找不到合适的 std::initializer_list
构造函数。
您 link 提出的问题与初始化向量时的歧义无关。歧义在于选择函数重载。两者都是可行的,因为它们都接受一个不同的向量,该向量本身可以从相同的初始化列表明确地初始化。
#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;
}
代码输出:
8
1
我知道这是 C++ 中的一个众所周知的问题,因为:
std::vector<std::size_t>(std::size_t{8})
调用
explicit vector(size_type count)
而
std::vector<std::size_t>{std::size_t{8}}
调用
vector(std::initializer_list<T> init, const Allocator& alloc = Allocator())
.
令我惊讶的是:
为什么第二次调用没有触发重载解析歧义的编译时错误?
因为不存在会导致错误的歧义。当我们使用列表初始化时,重载解决方案明显不同。这是有意分两个阶段完成的。
[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 ]
第一步只考虑 std::initializer_list
个构造函数。我们可以到达第二步,只有在第一次重载决议失败时才考虑其他构造函数。显然重载决议不会找不到合适的 std::initializer_list
构造函数。
您 link 提出的问题与初始化向量时的歧义无关。歧义在于选择函数重载。两者都是可行的,因为它们都接受一个不同的向量,该向量本身可以从相同的初始化列表明确地初始化。