为何无法隐式转换的类型会引发大括号初始化列表的重载调用歧义?
C++重载函数调用歧义问题分析
先看给出的代码:
#include <type_traits> #include <vector> struct A { A(); }; static_assert(std::is_convertible_v<double, A> == false); static_assert(std::is_convertible_v<A, double> == false); void func(std::vector<double> values); void func(std::vector<A> as); int main() { func({ 4.2 }); }
结论:GCC和VC15报歧义的处理符合C++标准,是正确的。
原因分析:
当用{4.2}这种初始化列表调用重载的func时,编译器会对两个重载版本分别做可行性检查:
针对
func(std::vector<double>):std::vector<double>自带接受std::initializer_list<double>的构造函数,{4.2}可以直接匹配这个构造函数,属于精确匹配的用户定义转换序列。针对
func(std::vector<A>):
虽然double不能转换为A,没法用std::initializer_list<A>的构造函数,但std::vector<A>还有另一个构造函数:vector(size_type n, const A& val = A())。这里4.2作为单个元素的初始化列表,可以隐式转换为size_type(无符号整数类型,属于标准转换序列),然后调用这个构造函数(第二个参数用默认构造的A对象),因此这个重载版本也是可行的。
进入重载决议的排序阶段后,这两个可行调用对应的转换序列都是用户定义转换序列,且二者的转换路径没有优劣之分——一个是通过初始化列表直接构造vector<double>,另一个是通过将double转换为size_type构造vector<A>。根据C++标准,这种情况下编译器无法判定哪个重载更优,因此会报调用歧义的错误。
如果想让代码明确调用func(std::vector<double>)版本,可以显式构造容器:
func(std::vector<double>{4.2});
内容的提问来源于stack exchange,提问作者zjyhjqs
相关产品推荐
相关产品推荐

