Рассмотрим следующий код:
#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, и я хочу знать, в чем именно заключается различие.
Есть две возможные интерпретации tmp[3]
: «очевидный», вызывающий test_class::operator[](int32_t)
и менее очевидный, вызывающий test_class::operator const char*()
преобразовать объект в const char*
и применение индекса к этому указателю.
Чтобы решить, какую из перегрузок использовать, компилятор просматривает соответствующие преобразования. Для каждой перегрузки есть два аргумента: tmp
а также 3
, Для первой перегрузки tmp
не нуждается в преобразовании, но 3
должен быть преобразован из int
в int32_t
, Для второй перегрузки tmp
должен быть преобразован в const char*
, а также 3
не должен быть преобразован.
Чтобы выбрать правильную перегрузку, компилятор должен посмотреть набор преобразования для каждого аргумента. Для первого аргумента, tmp
первая перегрузка не требует преобразования, а вторая требует интегрального преобразования. Таким образом, первая перегрузка выигрывает здесь. Для второго аргумента первая перегрузка требует определенного пользователем преобразования, а вторая не требует преобразования. Итак, первое преобразование выигрывает.
Вкратце: первая перегрузка выигрывает у первого аргумента, а вторая перегрузка выигрывает у второго аргумента. Так что вызов неоднозначен.
Вы можете добавить перегруженный operator[](int)
, который решит эту конкретную жалобу, но это будет ошибка с компилятором, где int32_t
это синоним int
,
Ваш лучший выбор, вероятно, избавиться от operator[](int32_t)
и заменить его на operator[](int)
,
Вот почему вы должны тщательно подумать о типах фиксированного размера: вы можете получить конверсии, которые вы не ожидаете.
Других решений пока нет …