C++添加std::string版operator[]后foo[0]编译歧义问题咨询
问题解析:operator[]重载后的歧义问题
先还原你的代码场景,方便理解:
初始无歧义代码:
#include <string> class Foo { public: // const成员函数,参数为int int& operator[](int idx) const { static int dummy; return dummy; } // const成员函数,参数为const std::string& std::string& operator[](const std::string& key) const { static std::string dummy; return dummy; } }; int main() { Foo foo; foo[0]; // 正常编译 foo[1]; // 正常编译 }
添加非const的std::string版本后(出现歧义):
#include <string> class Foo { public: int& operator[](int idx) const { static int dummy; return dummy; } std::string& operator[](const std::string& key) const { static std::string dummy; return dummy; } // 新增:非const成员函数,参数为const std::string& std::string& operator[](const std::string& key) { static std::string dummy; return dummy; } }; int main() { Foo foo; foo[0]; // 编译错误:ambiguous overload for 'operator[]' foo[1]; // 仍正常编译 }
1. 为什么添加非const的std::string版本会导致foo[0]歧义?
这是C++重载决议规则和隐式转换共同作用的结果:
调用
foo[0]时,foo是非const对象,三个重载都属于可行函数:operator[](int) const:参数0是int,和参数类型精确匹配;但成员函数是const,调用时需要把foo从非const转换为const(这是cv限定转换)。operator[](const std::string&)(非const版):0作为整数是空指针常量,可隐式转换为const char*,再通过std::string的构造函数生成std::string(这是用户定义转换序列);成员函数是非const,和foo的cv属性完全匹配,无需转换。
重载决议中,两个函数的优势维度冲突:
operator[](int) const的参数转换序列更优(精确匹配优先级高于用户定义转换)。operator[](const std::string&)的对象转换序列更优(精确匹配优先级高于cv限定转换)。
C++标准中,这种跨维度的优势无法判定优先级,编译器无法确定你想调用哪个重载,因此抛出歧义错误。
而初始代码中只有const版的std::string重载,此时foo[0]的两个可行函数的对象转换序列都是cv限定转换,参数转换序列的优先级直接生效,编译器会选精确匹配的int版本,因此无歧义。
2. 为什么仅索引0存在该问题?
因为只有整数0是C++中的空指针常量,可以隐式转换为任意指针类型(包括const char*),进而生成std::string对象。
而整数1(或其他非0整数)不能被隐式转换为指针类型,自然无法生成std::string,因此两个std::string版本的重载都不属于可行函数,编译器只能选择int版本的重载,所以不会出现歧义。
内容的提问来源于stack exchange,提问作者albator
相关产品推荐
相关产品推荐

