2012-05-24 12 views
7

STL utilizza il "minore di" come comparatore predefinito. Una chiamata di confronto STL su un oggetto con wrapper reference_<>does not compile, anche se la classe sottostante ha definito l'operatore "<".Se std :: reference_wrapper contiene l'operatore di confronto "<" predefinito?

Sembra, questo è perché c'è no implicit conversion eseguita su sui LHS del LHS.operator < (SSR) quando è una funzione membro. Ho verificato che using a free version funziona come il comparatore.

Tuttavia, se il reference_wrapper ha fornito l'operatore "<", che chiama "<" sul sottostante, sarà necessario ovviare alla necessità di utilizzare la funzione libera.

ho fatto la seguente aggiunta nel codice per la reference_wrapper (tratto da VS11 Beta xrefwrap.h), e potrebbe utilizzare std :: map con una classe avvolto nella mia versione della reference_wrapper <> che ha la "<" operatore definito.

bool operator <(reference_wrapper<_Ty> const rhs) const { 
    return this->get() < rhs.get(); 
} 

aggiunto in seguito: Se ho capito bene, reference_wrapper <> fornisce copia/assegnare semantica associati PTR necessari per molte biblioteche, nascondendo la sintassi relativa ptr. Ciò consente l'uso della sintassi del tipo di riferimento, senza il sovraccarico delle copie locali. Per confrontarlo con esempi utilizzando ptrs manca completamente uno del punto del reference_wrappers: si desidera evitare l'uso della sintassi del tipo ptr.

Il modo in cui stanno le cose al momento, il codice che funziona direttamente sugli oggetti si interrompe quando gli oggetti vengono avvolti in reference_wrappers. Inutile dire che "<" è il comparatore predefinito, anzi lo rende speciale; in una percentuale significativa del codice esistente, gli oggetti definiranno questi per ovviare alla necessità di comparatori speciali.

Aggiunto in ritardo # 2: La cronologia di questa funzione suggerisce che evitare l'uso della sintassi di ptr non era l'intento originale. Tuttavia, è stato un decennio da quando è stato introdotto per la prima volta in boost. Con un gran numero di nuovi programmatori "guidati" to avoid ptr based syntax (indubbiamente influenzato dai linguaggi gratuiti di ptr), questa funzione può diventare sempre più utile se potesse funzionare in modo più fluido, specialmente quando si tratta di legacy code che memorizza oggetti in contenitori STL e copia di valore in tutto .

aggiunta successivamente # 3: Migliorare codice legacy con codice minimo cambia Nel corso del tempo le classi sottili diventano pesanti e la dimensione degli oggetti nei contenitori aumenta. Un modo rapido per migliorare le prestazioni consiste nell'evitare le copie, tramite oggetti avvolti. Ciò fornirà le prestazioni di tipo "C ptr" senza le copie aggiuntive con modifiche minime al codice.

std::map<const Object, string> objTable; 
// can be rewritten as to avoid object copies using the 
// __myOwn::reference_wrapper which contains the '<' operator 
std::map<__myOwn::reference_wrapper<const Object>, string> rwTable_myOwn; 

// which works with out any non-member free comparator functions 
rwTable_myOwn[a]="One"; // Compiles and works 

// When using the table with the std::reference_wrapper 
std::map<std::reference_wrapper<const Object>, string> rwTable_std; 
//the map does not work 
rwTable_std[a]="One"; // Fails to compile it needs the custom non-member comparator 
+0

@GManNickG Il <è il comparatore predefinito in STL e ha un posto speciale nell'STL. La domanda sul perché fermarsi al "<" è evidente. Per come stanno le cose adesso, potresti usare STL sugli oggetti grezzi con l'operatore "<" che esprime la semantica degli ordini, ma lo stesso codice si interromperà una volta avvolto. – VSOverFlow

+0

No, 'reference_wrapper' non è stato creato per sostituire i puntatori. È inteso come una sostituzione di riferimenti (da cui il nome). –

+0

Thx per le origini; @Xeo ha sottolineato anche questo (vedi risposta sotto). http://stackoverflow.com/a/9149473/1408646 suggerisce che esiste un elemento di stile quando si evita la sintassi di ptr. – VSOverFlow

risposta

9

No, non dovrebbe. Non è il lavoro di reference_wrapper fare qualsiasi cosa ma avvolgere un riferimento come valore.

Se avete bisogno di confrontare due reference_wrapper<T> s'(che non è un riferimento a T), allora è il vostro lavoro per fare quel lavoro.Per lo stesso motivo, std::set<T*> non definisce automaticamente il confronto come std::less<T>(*x, *y), né nel caso specifico. Il wrapper è solo un puntatore non nullo.

Perché fermarsi a un unico operatore di confronto o tutti gli operatori di confronto? Perché non sovraccaricare il wrapper di riferimento per all delle funzioni standard? Perché non ne vale la pena quando la soluzione è così semplice.

+0

Si riduce a perché reference_wrapper <> è stato creato in primo luogo. Da quello che ho capito, è di evitare la sintassi basata sul puntatore e attenersi alla sintassi basata sul riferimento, pur consentendo l'uso di librerie esistenti che prevedono la copia/assegnazione della semantica ed evitando copie non necessarie. L'esempio del set è ortogonale al problema da affrontare poiché utilizza esplicitamente la sintassi basata su ptr. L'altra domanda sul perché fermarsi a VSOverFlow

+2

@vsaxena: Penso che 'std :: [c] ref' e' std :: reference_wrapper' (o meglio, le loro controparti Boost) siano state originariamente create per cose come 'std :: thread',' std :: bind', 'std :: async', ecc. che ha bisogno di semantica del valore per gli argomenti passati alle funzioni, ma l'utente non vuole la semantica del valore (cioè copie). Questo in realtà non ha nulla a che fare con la semantica puntatore vs riferimento, ma piuttosto dando all'utente la scelta su come passare gli argomenti senza richiedere strane shenanigans sul lato dell'utente o dell'implementazione. – Xeo

+3

Immaginate se 'reference_wrapper' non esistesse. Si desidera l'argomento 'bind'' heavy_object a; 'per una funzione' void f (heavy_object const &) '. Una chiamata normale come 'bind (f, a)' creerà una copia all'interno dell'oggetto restituisce 'bind' (che è l'unico valore predefinito ragionevole). Si potrebbe usare 'bind (f, & a)' per memorizzare solo un puntatore, ma ora l'oggetto 'bind' non può più chiamare' f', poiché 'f' non si aspetta un puntatore. Non è possibile memorizzare per impostazione predefinita un riferimento all'argomento, poiché non si ha modo di ricavarne un valore che possa sopravvivere all'ambito degli argomenti originali. – Xeo

Problemi correlati