С++ неожиданное преобразование
Следующий код компилируется из-за неявного преобразования для char
. Я не уверен, почему, поскольку единственное неявное преобразование, которое я ожидал бы (и ожидал бы сбой), было от char const*
до size_t
.
#include <cstddef>
struct foo
{
int operator[](size_t i) const { return 1; }
operator char() const { return 'a'; }
};
int main()
{
foo f;
f["hello"]; // compilation error desired here
}
Что такое неявное преобразование здесь, которое позволяет это скомпилировать? Если я удалю operator char
или сделаю его explicit
, тогда компиляция завершится с ошибкой в нужном месте.
Класс, который действительно извлекается из этого кода, действительно требует как неявного преобразования, так и operator[]
. Так можно ли предотвратить поведение, не делая явное преобразование?
Ответы
Ответ 1
Причина, по которой компилируется строка, заключается в том, что с неявным преобразованием она может быть интерпретирована как 'a'["hello"];
, которая, в свою очередь, такая же, как и запись *(('a')+("hello"));
, которая также компилируется.
Выдержка для стандарта:
5.2.1 Подпись:
... выражение E1 [E2] идентично (по определению) к * ((E1) + (E2))...
Простейшим обходным решением без явного преобразования оператора преобразования является объявление оператора оскорбительного индекса как:
struct foo
{
operator char() const { return 'a'; }
int operator[](size_t i) const { return 1; }
// prevent accidental use of foo["hello"]
int operator[](char const*) const = delete;
};
Ответ 2
f["hello"];
переводится в f.operator [] (index), где index - это значение указателя, указывающего на "привет". В вашем случае он вызывает operator [] (size_t i). Таким образом, абсолютно нормально, что компилятор не жалуется. Фактически значение индекса будет значением l; arge (значение указателя), поэтому лучше быть осторожным при перегрузке [] и проверять верхнюю границу там
Фактически, если у вас есть:
char *c = "hello"; // c is a pointer
f[c]; // ok