如何避免 cast operator() 和 access operator[] 冲突?

How do I avoid cast operator() and access operator[] conflict?

我确定之前有人问过,但我找不到。

我有一个class封装std::string。在内部,我想将类型转换重载到 char* 和访问 operator[].

class String
{
public :
    String(const char* s) { m_str = s; }
    const char* str() const  { return m_str.c_str(); }
    char* str()  {  return &m_str[0]; }
    char operator[](size_t pos) const { return m_str[pos]; }
    char& operator[](size_t pos) { return m_str[pos]; }
    operator const char*() const { return str(); }  // cast operator
    operator char*() { return str(); }  // cast operator
protected:
    std::string m_str;
};

void main()
{
    String s = "1234";
    if(s[0] != '1')   //'String::operator []': 4 overloads have similar conversions !!!!!
        std::cout << "Error" << endl;
}

当然,当我尝试使用 String [] 时出现问题,我收到错误消息:

4 overloads have similar conversions

编译器无法决定要做什么:

  1. 直接使用重载operator[]
  2. 首先转换为 char*,使用 operator(),最后 operator[] 覆盖生成的 char* 数组

有什么方法可以保留这两个操作员吗?对于许多功能,char*const char* 对使用 Stringoperator() 非常有帮助,但在所有其他情况下直接使用 operator[](不尝试首先转换为 char*)。

我想这个问题的答案可能是。这就是为什么在 std::string 中没有 char* 转换运算符的原因,但也许在最近的 C++ 标准中发生了一些变化?

编辑: 我可以用 GCC 编译上面的代码,但它在 VS (x86) 中失败了。

Error C2666 'String::operator []': 4 overloads have similar conversions

始终在启用警告的情况下编译代码,对于 gccclang,命令行选项是 -Wall -Wextra -Werror。警告会告诉您 operator[] 需要 return 一个值。


在 32 位模式下的表达式 s[0]clangmsvc 编译器考虑 int 索引的 标准转换 unsigned(32 位 size_t)与 Stringchar* 用户定义转换 具有相同等级。请参阅编译器错误消息 here。后一种转换是 用户定义的转换 的排名比任何 标准转换 都要差,但编译器无法解决这种关系。我不确定这里适用哪个标准规则。

解决方法是添加另一个 operator[] 的重载,它接受签名的 ptrdiff_t 索引:

char operator[](ptrdiff_t pos) const { return m_str[pos]; }
char& operator[](ptrdiff_t pos) { return m_str[pos]; }