2012-04-19 7 views
12

Cuando intento compilar el siguiente (g ++ 4.6.3)Sobrecarga del operador C++: ¿no se conoce conversión de objeto a referencia?

class A {}; 

A& operator*=(A& a, const A& b) 
{ 
    return a; 
} 

A operator*(const A& a, const A& b) 
{ 
    return A(a) *= b; 
} 

int main(int, char*[]) 
{ 
    A a, b; 

    a = a*b; 

    return 0; 
} 

consigo el error

/tmp/test.cxx: In function ‘A operator*(const A&, const A&)’: 
/tmp/test.cxx:14:20: error: no match for ‘operator*=’ in ‘(* & a) *= b’ 
/tmp/test.cxx:14:20: note: candidate is: 
/tmp/test.cxx:6:1: note: A& operator*=(A&, const A&) 
/tmp/test.cxx:6:1: note: no known conversion for argument 1 from ‘A’ to ‘A&’ 

Esto me intriga - ¿cómo puede una conversión de una clase a una referencia a esa clase no ser conocido?

Cambio de la declaración de la clase A de la siguiente no tiene ningún efecto:

class A 
{ 
public: 
    A() {} 
    A(const A&) {} 
}; 

mismo error.

Estaría muy agradecido por las sugerencias sobre lo que está sucediendo aquí.

+0

Puede solucionar este problema al declarar el operador en el ámbito de la clase. Entonces su firma de método se vería así: 'Un operador * (const A & rhs) const;' Si desea utilizar el operador compuesto para la implementación, puede escribir: 'return * this * = rhs' – Paranaix

+0

@Paranaix: No, no puede usar 'operator * =' on '* this' dentro de un' const' función de miembro, ya que modificaría '* this'. –

+0

@BenVoigt: Sí, tienes razón. Quería escribirlo como un trazador de líneas y accidentalmente eliminé toda la magia. El truco es crear una copia de 'esto'. En el ejemplo: 'A ret = * this; ret * = rhs; return ret; ' – Paranaix

Respuesta

13

Como dijo Lucian, no puede vincular un objeto temporal a una referencia no constante. La expectativa del compilador es que el objeto dejará de existir después de la expresión, por lo que no tiene sentido modificarlo.

para fijar su código, retire el temporal (haciendo que el argumento const& no tiene sentido en operator *=):

A operator*(A a, const A& b) 
{ 
    return a *= b; 
} 
+0

@Ben Necesito café ... Para defender mi honor, este (paso por valor) es como normalmente lo escribiría cuando estoy despierto. –

+0

Mucho más simple. Y más optimizado, ya que puede moverse cuando el parámetro real es un valor x. –

5

Cuando se escribe A(a), se crea un temporal del tipo A (un valor de lado derecho) que copia -construir con a. C++ establece que no se puede pasar ningún valor r como referencia no constante. Visual Studio es un poco descuidado con respecto a esta regla, pero gcc y similares lo hacen cumplir.

Para solucionarlo, intente esto (que es exactamente lo mismo, pero crea un valor l nombrando esa variable). Más de L y R valor here

A operator*(A a, const A& b) 
{ 
    return a *= b; 
} 
+2

La misma objeción que publiqué en la respuesta de Konrad. –

+0

Ambos son correctos. Pero a veces, no necesita crear una copia de a para hacer la operación *. p.ej. El operador Vector * no usará * = para expresar * – crazyjul

+0

"Visual Studio es un poco descuidado con esta regla ...": Visual Studio detecta esto si se está ejecutando en el nivel de advertencia 4/trata las advertencias como errores (como es sabio) . – mwigdahl