2011-01-16 4 views
8

Considérez ce code,conversion implicite: référence const vs référence non-const vs non-référence

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); 
} 

Ce compiles fine, fonctionne très bien. Mais si je change f(B) en f(B&), il . Si j'écris f(const B&), c'est à nouveau compiles fine, fonctionne bien. Pourquoi est la raison et la raison?

Résumé:

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

Je voudrais entendre les raisons, la justification et référence (s) de la spécification du langage, pour chacun de ces cas. Bien sûr, les signatures de la fonction elles-mêmes ne sont pas incorrectes. Plutôt A convertit implicitement en B et const B&, mais pas en B&, et cela provoque l'erreur de compilation.

Répondre

7

Je voudrais entendre raisons, justification et référence (s) de la spécification du langage

est-La conception et l'évolution de C++ suffisante?

J'ai fait une grave erreur, mais, en permettant une référence non-const à initialiser par un non-lvalue [commentaire par moi: ce libellé est imprécis!]. Par exemple:

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

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

En raison de la différence dans le type le int& ne peut pas se référer à la double passé si temporaire a été généré pour tenir un int initialisé par la valeur de ss. Ainsi, incr() modifié le temporaire, et le résultat n'a pas été reflété à la fonction d'appel [emphase mine].

Pensez à ce sujet: Le point entier de l'appel par référence est que le client passe des choses qui sont modifiées par la fonction, et après le retour de la fonction, le client doit être en mesure d'observer les changements.

+0

Une chose intéressante: Dans l'ARM, la détermination de la lvalueness pour l'expression primaire est la suivante: "Le résultat est une lvalue si l'identificateur est." .. "Le résultat est une lvalue si le membre est.". Je me suis demandé ce que cela signifiait, car il définit aussi «Une lvalue est une expression se référant à un objet ou à une fonction». Hmm, peut-être que cela signifie simplement "Le résultat est une valeur si elle se réfère à un objet ou une fonction." –

+0

C'est bon. Je pense que cela répond mieux à ma question, car cela explique pourquoi ce n'est pas autorisé. J'accepte ceci comme réponse à ma question. :-) – Nawaz

4

Le problème est que la conversion implicite d'un objet en un objet B produit un rvalue. Les références non-const peuvent uniquement lier à lvalues.

Si B avait un constructeur par défaut, vous obtiendriez le même comportement si vous modifiez l'appel f(a) à f(B()).

-

litb fournit une excellente réponse à ce qui est une lvalue: 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?

-

Pour expliquer avec des références à la norme comment ces appels de fonction échouent ou réussissent seraient excessivement longs. L'important est comment B& b = a; échoue tandis que const B& b = a; n'échoue pas.

(de projet n1905)

Une référence au type « CV1 T1 » est initialisé par une expression de type « T2 CV2 » comme suit:
- [ est une lvalue et est soit référence compatible ou implicitement convertible en lvalue d'un type compatible de référence ... ]
- Dans le cas contraire, la référence doit être un type const non volatile (cv1 doit être const).

Here's un cas où quelque chose est convertible en un type compatible de lvalue de référence.

+0

Pourquoi est-ce que la question de @ Nawaz était restée sans réponse pendant 23 minutes, et quand je l'ai répondu, vous avez répondu 30 secondes avant moi. C'est magique! Haha, +1. –

+0

@Chris: S'il vous plaît citer également les références pertinentes, afin que je puisse explorer les concepts pertinents moi-même. – Nawaz

+3

Strictement parlant, vous ne pouvez pas créer de valeurs ou de valeurs lvalues, car la catégorie-valeur est un attribut de * expressions * (temps de compilation), pas * objets * (temps d'exécution). – fredoverflow