2012-10-06 32 views
11

Recientemente, han seguido una discusión acerca de las asignaciones a las expresiones en C++, como se muestra en el siguiente ejemplo:¿Debo usar calificadores de referencia lvalue para operadores de asignación?

string s1, s2, s3; 
(s1 + s2) = s3; 

con C++ 11 es posible restringir el operador de asignación para lValue referencias (en el lado izquierdo) Al declarar los operadores de asignación como sigue, el compilador Clang rechaza el código con un mensaje de error debido a tipos incompatibles.

auto operator=(const string& rhs) & -> string&; 
auto operator=(string&& rhs) & -> string&; 

No he visto esto en ninguna parte. ¿Existe una buena razón para no utilizar los calificadores de referencia de lvalue para los operadores de asignación (además de la falta de soporte en la mayoría de los compiladores)?

+5

Una de las razones es que la mayoría de los compiladores no son compatibles con la sintaxis todavía. Otra es que no resuelve un problema * mayor *. ¿Con qué frecuencia sucede esto por error? –

+1

Creo que sucede. 'if (somefunc() = value)' Por supuesto, la mayoría de los compiladores emiten una advertencia para esto, pero no en todos los casos. –

Respuesta

4

No, realmente no. El uso de los calificadores lvalue o rvalue para construir una interfaz correcta para los objetos lvalue o rvalue es exactamente lo mismo que usar const, y debe enfocarse de la misma manera; cada función se debe considerar como una restricción. La asignación a un rvalue realmente no tiene sentido, por lo que debería estar prohibido.

La razón por la que no lo ha visto es en su mayoría pobres compilador SOPORTE- árbitros rvalue para *this es un poco como thread_local, la mayoría de los ejecutores del compilador parecen haber ponerlo cerca de la parte inferior de las "Características de implementar desde C++ 11" apilar.

+0

En mi opinión, la mejor respuesta. Aunque estaba más interesado en el operador de asignación, porque es una función de miembro especial. El uso de calificadores de referencia puede tener algún efecto en la regla de 5, herencia, siendo una variable miembro de un agregado o uso con contenedores estándar y la biblioteca estándar. Sin embargo, debería haber estado pidiendo esta información. – nosid

8

¡Interesante! Ni siquiera estaba al tanto de esto y me tomó un tiempo encontrarlo (era parte de la propuesta "Extending move semantics to *this"). La notación se define en 8.3.5 [dcl.decl] párrafo 4 en caso de que alguien quiera echar un vistazo.

De todos modos: ahora, conociendo esta característica, parece que es más útil usarlo para sobrecargar y posiblemente comportarse de manera diferente si el objeto al que se llama una función es un valor l o un valor r. Usarlo para restringir lo que se puede hacer, por ejemplo, con el resultado de una tarea parece innecesario, especialmente si el objeto realmente es un valor l. Por ejemplo, es posible que desee la sintaxis para devolver un valor de lado derecho de asignar a un valor p:

struct T { 
    auto operator=(T&) & -> T&; 
    auto operator=(T&&) & -> T&; 
    auto operator=(T&) && -> T; 
    auto operator=(T&&) && -> T; 
}; 

La intención sería la de permitir que se mueve a partir del resultado de asignación (si es que vale la pena, sin embargo, no estoy seguro: ¿por qué no omitir la tarea en primer lugar?). No creo que use esta característica principalmente para restringir los usos.

Personalmente, me gusta la posibilidad de obtener a veces un lvalue de un valor r y el operador de asignación suele ser una forma de hacerlo. Por ejemplo, si usted necesita para pasar un valor-I a una función, pero usted sabe que no desea utilizar cualquier cosa con él, puede utilizar el operador de asignación hacerse con un valor-i:

#include <vector> 
void f(std::vector<int>&); 
int main() 
{ 
    f(std::vector<int>() = std::vector<int>(10)); 
} 

Ésta puede ser una abuso del operador de asignación para obtener un lvalue de un valor r pero es poco probable que ocurra por accidente. Por lo tanto, no saldría de mi camino y lo haría imposible al restringir el operador de asignación para que sea aplicable solo a los valores l. Por supuesto, devolver un valor r de una asignación a un valor r también evitaría esto. Cuál de los dos usos es más útil, si lo hay, podría ser una consideración.

BTW, clang parece ser compatible con la sintaxis que citó desde la versión 2.9.

+5

Preferiría tener una plantilla ' clara T & as_lvalue (T && v) {return v; } 'función que atornillar con las mentes de mis codificadores compañeros que se preguntan qué diablos estás tratando de lograr con la tarea (que, para el movimiento-inconsciente, también parece incluir una copia inútil del' vector'). – Xeo

3

Una razón por la que no estoy súper entusiasmado con su sugerencia es que I'm trying to shy away from declaring special members altogether. La mayoría de mis operadores de asignación están implícitamente declarados y, por lo tanto, no tienen ref-calificadores.

Por supuesto, para aquellos momentos en los que hago escribir una plantilla de clase o clase a, por ejemplo administrar la propiedad (ver conclusión en el enlace anterior), podría tener la precaución de declarar esos operadores solo para los valores l. Sin embargo, dado que no tiene efectos en los clientes, no tiene mucho sentido.

+0

Estoy de acuerdo con usted. Si es posible, evito declarar cualquiera de los 5. Sin embargo, el operador de asignación generado por el compilador no está restringido a las referencias de valor l. Lo más probable es que sea compatible con versiones anteriores. – nosid

Cuestiones relacionadas