添加uint32_t转换运算符后,operator[]出现编译歧义问题求助
问题分析:添加uint32_t转换运算符后operator[]出现歧义编译错误
问题背景
原本可正常编译的代码如下:
#include <iostream> #include <map> #include <memory> using namespace std; class child { public: child(std::string name,uint32_t age) : name(name),age(age){ } std::string name; uint32_t age; }; class parent { public: uint32_t age; parent(std::string name){ age = 10; } std::map<uint32_t, std::shared_ptr<child>> child_by_age; std::map<std::string, std::shared_ptr<child>> child_by_name; child& operator[](const uint32_t& num){ return *(child_by_age[num]); } child& operator[](const std::string& n){ return *(child_by_name[n]); } void addChild(const child& ch){ auto ch_obj = std::make_shared<child>(ch); child_by_age.emplace(ch.age, ch_obj); child_by_name.emplace(ch.name, ch_obj); } }; class top { public: parent p1; top():p1("p1"){ p1.addChild(child("c0",0)); p1.addChild(child("c1",1)); } void run(){ p1["c0"].name = "name"; p1[0].name = "name1"; } }; int main(){ top t; t.run(); return 0; }
在parent类中添加以下转换运算符后:
operator uint32_t() const{ return age; }
编译时出现如下错误:
operator_overload.cpp: In member function ‘void top::run()’: operator_overload.cpp:50:11: error: ambiguous overload for ‘operator[]’ (operand types are ‘parent’ and ‘const char [3]’) p1["c0"].name = "name"; ^ operator_overload.cpp:50:11: note: candidate: operator[](long int, const char*) <built-in> operator_overload.cpp:28:12: note: candidate: child& parent::operator[](const string&) child& parent::operator[](const std::string& n){ ^~~~~~~~
错误原因
问题根源在于C++的重载解析规则:
- 未添加转换运算符时,
p1["c0"]的匹配逻辑很清晰:"c0"是const char[3]类型,可隐式转换为std::string,因此编译器会选择parent::operator[](const std::string&),无歧义。 - 添加
operator uint32_t()后,出现了第二种合法的重载路径:- C++存在内置的
operator[],支持整数[字符串]的写法(等价于字符串[整数]),参数类型为(long int, const char*)。 - 编译器现在可以做两种优先级相同的隐式转换:
- 把
const char[3]转为std::string,调用类成员的operator[](const std::string&) - 把
parent对象通过转换运算符转为整数,调用内置的operator[](long int, const char*)
两种路径的转换成本一致,编译器无法判断优先级,因此抛出歧义错误。
- 把
- C++存在内置的
解决方案
有三种可行的解决方式:
- 限制转换运算符的隐式使用:用
explicit修饰转换运算符,仅允许显式强制类型转换时生效,避免隐式转换干扰重载解析:explicit operator uint32_t() const{ return age; } - 显式转换调用参数:在调用
operator[]时,把字符串显式转为std::string,消除歧义:p1[std::string("c0")].name = "name"; - 新增匹配
const char*的重载:在parent类中添加针对const char*的operator[],直接转发到std::string版本,让编译器优先选择类成员重载:child& operator[](const char* n){ return this->operator[](std::string(n)); }
内容的提问来源于stack exchange,提问作者KPathak
相关产品推荐
相关产品推荐

