嵌套大括号初始化列表构造对象在GCC/Clang下编译报重载歧义错误(VS可正常编译)
嵌套大括号初始化列表构造对象在GCC/Clang下编译报重载歧义错误(VS可正常编译)
嘿,最近踩了个跨编译器的小坑,必须来跟大伙唠唠!我有个程序在Visual Studio里编译运行都顺得不行,结果移植到GCC或者Clang上直接就卡壳了,报了个重载歧义的错误。我把代码精简到最核心的复现示例,大家瞅一眼:
#include <vector> struct A { A(const std::vector<int> &) {} }; A a( { { 1, 2 } } );
GCC和Clang报的错误一模一样:
error: call of overloaded 'A(
)' is ambiguous
为啥VS能过,GCC/Clang就不行呢?其实是不同编译器对C++初始化规则的实现细节差异搞的鬼。咱们拆解一下这个A({{1,2}})的初始化过程:
- 我们本来想让内层的
{1,2}先构造出一个std::vector<int>,再传给A的构造函数; - 但
std::vector本身有两个构造函数能匹配{1,2}:一个是接受initializer_list<int>的(直接生成包含1、2的vector),另一个是接受(size_type, const T&)的(生成包含1个元素2的vector); - VS的编译器会优先选择
initializer_list版本的构造函数,所以没歧义;但GCC和Clang会把这两个构造函数视为优先级相同的候选,这就导致外层调用A的构造函数时,编译器不知道该选哪条路径,直接报歧义了。
我试了几个办法都能搞定这个问题,给大伙参考:
- 显式构造
std::vector:把代码改成A a( std::vector<int>{1, 2} );,直接明确告诉编译器用哪个方式生成vector,从根源上消除歧义; - 改用列表初始化语法:把圆括号换成大括号,写成
A a{ {1, 2} };,这样编译器会优先按列表初始化的规则处理,直接匹配到vector的initializer_list构造函数; - (可选)给A加一个接受
std::initializer_list<int>的构造函数:如果业务逻辑允许的话,这样也能让编译器直接匹配到对应的构造函数,不过这个得看你的实际需求来定。
备注:内容来源于stack exchange,提问作者Fedor
相关产品推荐
相关产品推荐

