[英]Use of overloaded oeprator[] is ambiguous
簡化代碼如下:
#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
我很困惑,哪個編譯器是正確的?
template <typename T> operator T(){ return object{}; }
我認為 clang 在這里是正確的,因為這個片段使foo
class 可以轉換為任何類型,並且應該在重載決議發揮作用之前實例化可行的模板函數:
在重載決議開始之前,通過名稱查找和模板參數推導選擇的函數組合起來形成候選函數集
如您所見,重載與以下 arguments: (long, const char*)
相沖突,因此它必須是類似於此3["a"]
表達式,根據cppreference是完全合法的:
expr1 [ expr2 ]
對於內置運算符,其中一個表達式(
expr1
或expr2
)必須是“T
數組”類型的泛左值或“指向 T 的指針”類型的純右值,而另一個表達式(分別為expr2
或expr1
)必須是無作用域枚舉或整數類型的純右值。 此表達式的結果類型為T
然而,它也提供了如何區分內置下標和自定義重載的線索:
expr1 [ { expr, ... } ]
方括號內帶有大括號的列表的形式僅用於調用重載的
operator[]
。
所以如果上述例子是這樣寫的,你應該很好:
int main(){
foo f;
std::string s = f[{"a"}];
return 0;
}
或者將下標顯式轉換為字符串,因此編譯器不會將其與 arrays 的內置運算符混淆:
int main(){
using namespace std::string_literals;
foo f;
std::string s = f["a"s];
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.