С++ Назначить неявно преобразованное значение 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;
}
Почему это не компилируется? Есть ли конкретная причина, по которой это не было включено в стандарт С++? Или эквивалент действительно существует, и я просто использую его неправильно?
Ответы
Ответ 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;