【发布时间】:2018-09-11 10:49:49
【问题描述】:
考虑以下代码:
#include <stdio.h>
#include <stdint.h>
class test_class
{
public:
test_class() {}
~test_class() {}
const int32_t operator[](uint32_t index) const
{
return (int32_t)index;
}
operator const char *() const
{
return "Hello World";
}
};
int main(void)
{
test_class tmp;
printf("%d\n", tmp[3]);
return 0;
}
当我使用命令 clang++ -arch i386 test.cc 构建这些代码时,它会在 clang++ 上产生以下内容(Apple LLVM 版本 9.1.0 (clang-902.0.39.1)):
test.cc:24:21: error: use of overloaded operator '[]' is ambiguous (with operand types 'test_class' and 'int')
printf("%d\n", tmp[3]);
~~~^~
test.cc:10:17: note: candidate function
const int32_t operator[](uint32_t index) const
^
test.cc:24:21: note: built-in candidate operator[](const char *, int)
printf("%d\n", tmp[3]);
^
test.cc:24:21: note: built-in candidate operator[](const volatile char *, int)
但是如果我只使用命令clang++ test.cc没有错误
i386 上的重载运算符 '[]' 似乎与 x86_64 上的不同,我想知道具体的区别是什么。
【问题讨论】:
-
不知道为什么 2 个版本有差异。但是 i386 构建失败的原因是编译器可以使用用户提供的转换运算符然后索引 char 数组,或者只是索引变量。
-
@RichardCritten,要调用重载
operator[](char *,int),第一个参数是由用户定义的转换构造的,因此它的等级应低于其他重载。我无法重现它,但它看起来像一个 clang 错误。 -
@Oliv 使用
g++ -m32 test.cc会产生“警告:ISO C++ 说这些是模棱两可的,即使第一个的最差转换优于第二个的最差转换”,以及 g++ 的版本是 (Ubuntu 7.2.0-8ubuntu3) 7.2.0 。但是 clang 认为这是一个错误。 -
当一个类同时提供接受整数参数的
operator[]()以及转换为支持数组语法的任何类型(指针或类型为它自己的operator[]()。粗略的经验法则:要么提供operator[](),要么提供到指针类型的转换,而不是两者兼而有之。此外,无论如何解决歧义,printf("%d", tmp[3])都会给出未定义的行为,因为两者都没有可能性给出int类型的结果。 -
@NinetyPercent - 因为在不同的构建中,
int32_t的大小可能相同,但像int这样的基本类型(包括文字3)的大小不同。这会影响整数类型的排名(在您的情况下),进而会影响operator[]()函数的调用是否优于类型转换运算符。因此,适用于一种构建的东西可能不适用于另一种构建。这也是为什么最近的标准说这些东西是模棱两可的——因为实现之间存在差异[不同的构建相当于使用不同的实现,比如 32 位和 64 位编译器]。
标签: c++ operator-overloading x86-64 clang++ i386