Подтвердить что ты не робот

С++ неожиданное преобразование

Следующий код компилируется из-за неявного преобразования для 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[]. Так можно ли предотвратить поведение, не делая явное преобразование?

4b9b3361

Ответ 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