使用重载运算符[]存在歧义。

3
以下是简化版的代码:
#include <string>
#include <string_view>

struct object{
  operator std::string(){return "";}
}

struct foo{
  foo operator[](std::string_view s){
    return foo{};
  }
  
  template <typename T>
  operator T(){
    return object{};
  }
};

int main(){
  foo f;
  std::string s = f["a"];
}

clang 报错:

error: use of overloaded oeprator '[]' is ambiguous (with oeprand types 'foo' and 'const char*')
note: candidate function foo operator[](std::string_view s)
note: built-in candidate operator[](long, const char*)
note: built-in candidate operator[](long, const volatile char*)

但gcc成功编译了上述代码。

clang版本为12.0.1,gcc版本为7.5.0。

我很困惑,哪个编译器是正确的?


3
请确保您复制并粘贴想要展示给我们的代码和错误信息。这样做可以避免添加无关的错误和拼写错误。请不要在问题中重新编写它们。此外,请花些时间阅读帮助页面,参观SO [导览],阅读[提问指南]以及此问题清单 - Some programmer dude
2
你的代码中有这么多错别字,甚至无法编译。 - Raildex
1
抱歉,我认为我已经修复了拼写错误。我现在无法直接复制粘贴它们,因为我的开发环境是一个没有网络连接的虚拟机。评论并不重要,我已经将其删除。 - user9132451
1
您可以独立测试您提供给我们的代码,以确保它能够重现错误。 - HolyBlackCat
3
有趣的事实:"foo"[3] == 3["foo"] - Patrick Roberts
显示剩余2条评论
1个回答

2
template <typename T>
operator T(){
    return object{};
}
我认为clang在这里是正确的,因为此片段使得foo类可转换为任何类型,并且可能的模板函数应该在重载解析之前被实例化

在重载解析开始之前,名称查找和模板参数推导所选定的函数将被合并以形成候选函数集

如您所见,重载处理以下参数时会出现问题:(long, const char*),因此必须使用类似于3["a"]的表达式,根据cppreference,这是完全合法的:
expr1 [ expr2 ]

For the built-in operator, one of the expressions (either expr1 or expr2) must be a glvalue of type “array of T” or a prvalue of type “pointer to T”, while the other expression (expr2 or expr1, respectively) must be a prvalue of unscoped enumeration or integral type. The result of this expression has the type T

然而,它也提供了一种区分内置下标和自定义重载的线索:
expr1 [ { expr, ... } ]

The form with brace-enclosed list inside the square brackets is only used to call an overloaded operator[].

如果所举的例子是这样写的,那么你应该没问题:

因此,如果所示的示例是这样编写的:

int main(){
    foo f;
    std::string s = f[{"a"}];
    return 0;
}

或者将下标显式地转换为字符串,这样编译器就不会将其与数组的内置运算符混淆:
int main(){
    using namespace std::string_literals;
    
    foo f;
    std::string s = f["a"s];
    return 0;
}

2
你的修改是不正确的,返回值类型对于重载决议没有影响,因此 char 无法转换为 std::string 的事实并不会改变 operator[] 的解析。 - Holt
我同意@Holt的观点。同样的问题,没有涉及std::string:https://godbolt.org/z/xsoxofPzT。 - Daniel Langr
@Holt,感谢您的意见。已回滚编辑。 - The Dreams Wind

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接