2011-01-16 10 views
8

Considere este código,conversión implícita: referencia constante vs referencia no const vs no es de referencia

struct A {}; 
struct B { B(const A&) {} }; 
void f(B) 
{ 
    cout << "f()"<<endl; 
} 
void g(A &a) 
{ 
    cout << "g()" <<endl; 
    f(a); //a is implicitly converted into B. 
} 
int main() 
{ 
    A a; 
    g(a); 
} 

Este compiles fine, funciona muy bien. Pero si cambio f(B) a f(B&), es doesn't compile. Si escribo f(const B&), de nuevo compiles fine, funciona bien. ¿Por qué razón y razón de ser?

Resumen:

void f(B);   //okay 
void f(B&);  //error 
void f(const B&); //okay 

me gustaría escuchar razones, fundamentos y de referencia (s) de la especificación del lenguaje, para cada uno de estos casos. Por supuesto, las firmas de función en sí mismas no son incorrectas. Más bien A se convierte implícitamente en B y const B&, pero no en B&, y eso causa el error de compilación.

Respuesta

7

me gustaría escuchar razones, fundamentos y referencia (s) a partir de la especificación del lenguaje

Es El Diseño y Evolución de C++ suficiente?

di un grave error, sin embargo, al permitir que una referencia no const a ser inicializado por un no-valor-I [comentario por mí: que la redacción es imprecisa!]. Por ejemplo:

void incr(int& rr) { ++rr; } 

void g() 
{ 
    double ss = 1; 
    incr(ss); // note: double passed, int expected 
       // (fixed: error in release 2.0) 
} 

Debido a la diferencia en el tipo de la int& no puede referirse a la double pasado por lo que una temporal se generó para mantener un int inicializado por ss 's valor. Por lo tanto, incr() modificó el temporal, y el resultado no se reflejó de nuevo a la función de llamada [énfasis mío].

Piense en esto: El punto de llamada por referencia es que el cliente pasa a las cosas que son modificados por la función, y después de la función regresa, el cliente debe ser capaz de observar los cambios.

+0

Una cosa interesante: en el ARM, la determinación de lvalueness para primary-expression es la siguiente: "El resultado es un lvalue si el identificador es". .. "El resultado es un lvalue si el miembro es". Me he preguntado qué diablos debería significar, porque también define "Un lvalue es una expresión que se refiere a un objeto o función". Hmm, tal vez solo signifique "El resultado es un lvalue si se refiere a un objeto o función". –

+0

Esto es bueno. Creo que es mejor responder a mi pregunta, ya que explica por qué no está permitido. Estoy aceptando esto como respuesta a mi pregunta. :-) – Nawaz

4

El problema es que la conversión implícita de un objeto B produce un valor r. Las referencias non-const solo pueden enlazarse a lvalues.

Si B tenía un constructor predeterminado, obtendría el mismo comportamiento si cambia la llamada f(a) al f(B()).

-

litb proporciona una gran respuesta a lo que es un valor-i: Stack Overflow - often used seldom defined terms: lvalue

GotW #88: A Candidate For the “Most Important const”

Stack Overflow - How come a non-const reference cannot bind to a temporary object?

-

Para explicar con referencia a la norma de cómo esas llamadas de función fallar o tener éxito serían excesivamente largas. Lo importante es cómo B& b = a; falla, mientras que const B& b = a; no falla.

(de proyecto n1905)

Una referencia a escribir “CV1 T1” se inicializa por una expresión de tipo “cv2 T2” como sigue:
- [ es un lvalue y es o bien de referencia compatible o implícitamente convertible a un valor l de un tipo compatible con la referencia ... ]
- De lo contrario, la referencia será a un tipo de const no volátil (es decir, cv1 será const).

Here's un caso donde algo es convertible a un lvalue de tipo compatible con la referencia.

+0

¿Por qué la pregunta de @Nawaz no fue respondida durante 23 minutos, y cuando la supere, proporcionaste una respuesta 30 segundos antes que yo? ¡Eso es magia! Jaja, +1. –

+0

@Chris: por favor cite las referencias relevantes también, para que yo pueda explorar los conceptos relevantes yo mismo. – Nawaz

+3

Estrictamente hablando, no puede crear lvalues ​​o rvalues ​​en absoluto, ya que la categoría de valor es un atributo de * expressions * (compile time), no * objects * (runtime). – fredoverflow

Cuestiones relacionadas