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

С++ Назначить неявно преобразованное значение lvalue

Рассмотрим этот фрагмент кода С++:

struct Foo {
    float value;

    operator float& () {
        return this->value;
    }
};

int main() {
    Foo foo;
    foo=1.0f;   //Doesn't compile, foo isn't implicitly converted to a float&

    return 0;
}

Почему это не компилируется? Есть ли конкретная причина, по которой это не было включено в стандарт С++? Или эквивалент действительно существует, и я просто использую его неправильно?

4b9b3361

Ответ 1

Для почти всех других операторов оператор преобразования будет делать именно то, что вы хотите, и он будет продолжать делать именно то, что вы хотите, даже если вы добавляете настраиваемых операторов.

struct Foo {
    float value;
    operator float& () { return this->value; }
    Foo &operator+=(Foo);
};
int main() {
    Foo foo {};
    foo+=1.0; // compiles and works
    // equivalent to foo.operator float&()+=1.0;
}

Однако = является особенным, правила для = отличаются от большинства других операторов. Как определено T.C.:

13.3.1.2 Операторы в выражениях [over.match.oper]

4 Для встроенных операторов присваивания преобразования левого операнда ограничены следующим образом:
(4.1) - для ввода левого операнда не введены временные ряды, и
(4.2) - никакие пользовательские преобразования не применяются к левому операнду для достижения соответствия типа с самым левым параметром встроенного кандидата.

Вместе с тем, что любой пользовательский operator= не может быть определен как глобальная функция, это гарантирует, что foo=bar;, где foo - тип класса, всегда означает foo.operator=(bar);, ничего больше.

Тот факт, что этот один оператор выделен, не объясняет причину, но делает совершенно ясным, что это намеренное решение и убедившись, что foo=bar; всегда означает foo.operator=(bar);, ничего больше, само по себе уже кажется действительной причиной.

Ответ 2

Неявное преобразование выполняется только в следующих случаях:

Неявные преобразования выполняются всякий раз, когда выражение какого-либо типа T1 используется в контексте, который не принимает этот тип, но принимает некоторые другой тип T2; в частности:

  • когда выражение используется в качестве аргумента при вызове функции, объявленной с параметром T2 в качестве параметра;
  • когда выражение используется как операнд с оператором, который ожидает T2;
  • при инициализации нового объекта типа T2, включая оператор return в функции, возвращающей T2;
  • когда выражение используется в операторе switch (T2 является интегральным типом);
  • когда выражение используется в выражении if или в цикле (T2 - bool).

Ничего из этого не происходит. Вместо этого компилятор пытается найти подходящий operator= для работы с double. Чтобы выполнить эту компиляцию, вам необходимо перегрузить этот оператор (вы действительно хотите float, как показано в коде):

Foo& operator=(float other)
{
  value = f;
  return *this;
}

И измените ваше назначение на foo = 1.0f;

Ваша функция преобразования будет работать, например:

float f = foo;