c++ - Operador de sobrecarga[] y NO obtiene el error de "lvalor requerido como operando de asignaciĆ³n izquierdo"
operator-overloading lvalue (2)
¿Hay alguna manera de hacer que esto se queje?
Puede utilizar un operador de asignación predeterminado por defecto con un calificador de referencia:
struct Bar {
Bar& operator=(const Bar&) & = default;
// ^
Esto hace que la asignación de un valor no esté bien formada, mientras que la asignación de un valor lime permanece bien formada.
Tenga en cuenta que declarar el operador de asignación deshabilita la asignación de movimiento implícita, por lo que es posible que también deba definirlo, si es necesario (también como predeterminado, y posiblemente con un calificador de referencia de valor de r, si corresponde).
¿Por qué no se quejaría de la misma manera si Bar es temporal y no tiene un operador especializado =?
Porque los operadores de asignación generados implícitamente no son ref-calificados.
Claramente, este es un error de codificación si se usara de esta manera
La asignación de un valor no es universalmente un error. Para algunos tipos que se supone que se comportan como referencias, la asignación de un valor es natural. Esto es así porque la asignación modifica el objeto referido, y no el objeto temporal en sí.
Un caso de uso típico es la asignación a rvalue
std::tie
(ejemplo de
cppreference
):
std::set<S> set_of_s; // S is LessThanComparable
S value{42, "Test", 3.14};
std::set<S>::iterator iter;
bool inserted;
// unpacks the return value of insert into iter and inserted
std::tie(iter, inserted) = set_of_s.insert(value);
Sí, podría ser mejor si los operadores implícitos estuvieran calificados y se requiriera una declaración explícita para los no calificados, considerando que los tipos de referencia son excepcionales en lugar de la norma. Pero no es así como es el lenguaje y cambiarlo es un cambio incompatible hacia atrás.
Esto es un poco inverso de todas las preguntas de error de "lvalor requerido como operando de asignación izquierdo".
Tengo una clase que sobrecarga al operador [], pero solo la versión que devuelve un temporal.
Si fuera a devolver un int:
struct Foo
{
int operator[]( int idx ) const { return int( 0 ); }
};
Foo f;
f[1] = 5;
Obtendría con razón el error del compilador lvalue. Sin embargo, si devuelve un tipo de estructura, el compilador (GCC 7.2 en este caso) no se queja en absoluto:
struct Bar {};
struct Foo
{
Bar operator[]( int idx ) const { return Bar(); }
};
Foo f;
f[1] = Bar();
¿Por qué no se quejaría de la misma manera si Bar es temporal y no tiene un operador especializado =? Pregunta alternativa, ¿hay alguna manera de hacer que esta queja? Claramente, este es un error de codificación si se usara de esta manera
Sí, hay una manera de convertir esto en un error de compilación al eliminar estos métodos:
Bar& operator=(const Bar&)&& =delete;
Bar& operator=(Bar&&)&& =delete;
Solo tenga en cuenta que esto deshabilitará la generación automática de los otros operadores y constructores, por lo que tendrá que definirlos todos:
struct Bar {
Bar()=default;
Bar(const Bar&) = default;
Bar& operator=(const Bar&)&& =delete;
Bar& operator=(Bar&&)&& =delete;
Bar& operator=(const Bar&)& =default;
Bar& operator=(Bar&&)& =default;
};