2015-05-22 12 views
19

Considerate questo codice:Perché specificare un riferimento lvalue per * questo su una funzione membro è diverso dal non specificare nulla?

#include <iostream> 
using namespace std; 

struct A { 
    void f() { cout << "A::f" << endl; } 
    void f() const { cout << "A::f const" << endl; } 
}; 

struct B { 
    void f() & { cout << "B::f &" << endl; } 
    void f() const & { cout << "B::f const &" << endl; } 
}; 

A getA() { return A{}; } 
B getB() { return B{}; } 

int main() { 
    getA().f(); 
    getB().f(); 
} 

che stampa

A::f 
B::f const & 

Per B, viene selezionato il sovraccarico const, non quella non-const. Immagino che questo significhi che specificare un qualificatore di riferimento lvalue per * questo è diverso dal non specificare nulla. Perché? Il "implicito questo argomento" cambia tipo e il sovraccarico const diventa ora un candidato migliore nella risoluzione di sovraccarico?

+0

'B :: f' viene chiamato su un' B && '. Dal momento che non è possibile convertire un riferimento di rvalore in un riferimento a lvalue (a meno che non si tratti di Visual Studio), non è possibile chiamare 'B :: f &'. Non so se 'A :: f' è uguale a' A :: f && '. – nwp

+0

@nwp non lo è, 'A :: f() &&' può _only_ essere chiamato su rvalue. –

+0

Il trucco qui è che ref-qualificatore 'const &' può legarsi a un valore! (rendendolo abbastanza inutile) –

risposta

19

In questo caso:

struct A { 
    void f() { cout << "A::f" << endl; } 
    void f() const { cout << "A::f const" << endl; } 
}; 

getA().f(); 

Entrambi i sovraccarichi sono vitali per f, ma quello non-const è preferito perché non richiede alcuna conversione.

Ma in questo caso:

struct B { 
    void f() & { cout << "B::f &" << endl; } 
    void f() const & { cout << "B::f const &" << endl; } 
}; 

getB().f(); 

Il primo overload richiede this di essere un lvalue. Ma in getB().f(), il risultato di getB() è un valore di prval, che non può essere associato a un valore non costante. Quindi questo sovraccarico non è fattibile e non selezionato.

Il secondo sovraccarico richiede tuttavia che this sia un valore const, a cui può associare un valore di prvalue: questo overload è fattibile e selezionato dal compilatore.

+0

Capisco perfettamente quella parte, ma riguardo * non * specificando qualificatori di riferimento su 'f()'? Fondamentalmente l'intero punto è ora quello che dice che '&' equivale a non avere un qualificatore ref è falso. – peppe

+0

Scusa, potresti riformulare? Ottengo un errore di analisi sulla seconda frase. '&' non è equivalente a non avere un qualificatore di ref, perché limita a cosa può essere associato il metodo, se è questo che intendevi. I metodi qualificati non ref possono legarsi a qualsiasi categoria di valore. –

+4

Naturalmente aggiungere un qualificatore di ref è diverso dal non avere un qualificatore di riferimento, altrimenti quale sarebbe il punto della caratteristica ?! Cosa ti ha dato l'idea che "' & 'è equivalente a non avere un qualificatore di riferimento" potrebbe essere vero in primo luogo? –

6

Per riferimento, la frase che totalmente fuorviato me è in [over.match.funcs], §13.3.1/4 di N3337:

  1. Per le funzioni di membro non statici, il tipo del parametro oggetto implicito è

- “riferimento Ivalue a cv X” per funzioni dichiarate senza un ref-qualificazione o con il & ref-qualificazione

- “rvalue riferimento alla cv X” per le funzioni dichiarate con la & & ref-qualificazione

(sottolineatura mia).

Quindi stavo diventando un po 'pazzo sul perché c'era una differenza nell'output. Senza o con un qualificatore di riferimento & dovrebbe essere lo stesso secondo qui, giusto?

Beh, il motivo è una regola aggiuntiva nascosto in poi in §13.3.1/5

Per le funzioni di membro non statiche dichiarate senza un ref-qualificazione, una regola aggiuntiva si applica:

- anche se il parametro oggetto implicito non è const-qualificato, un valore rvalue può essere associato al parametro fintanto che in tutti gli altri aspetti l'argomento può essere convertito nel tipo del parametro oggetto implicito.

che innesca fondamentalmente la rvalue non-const alla conversione lvalue non const e rende la differenza nell'esempio di cui sopra. D'uh.

+0

Di solito, se sono confuso su come funzioni un C++ 11/14, controllo la carta che ha proposto la funzione, che ha una sezione di testo che mostra tutte le modifiche apportate allo standard, e spesso la logica dietro la proposta o un puntatore a una versione precedente che contiene la motivazione. In questo caso, sarebbe [N2439] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2439.htm). Le persone di GCC hanno una lista utile per tutti [C++ 11] (https://gcc.gnu.org/projects/cxx0x.html) e [C++ 14] (https://gcc.gnu.org/ projects/cxx1y.html) caratteristiche che si collegano alla carta corrispondente. –

Problemi correlati