2013-08-08 16 views
27

Sto cercando di capire std::reference_wrapper.Come utilizzare correttamente std :: reference_wrappers

Il seguente codice mostra che il wrapper di riferimento non si comporta esattamente come un riferimento.

#include <iostream> 
#include <vector> 
#include <functional> 

int main() 
{ 
    std::vector<int> numbers = {1, 3, 0, -8, 5, 3, 1}; 

    auto referenceWrapper = std::ref(numbers); 
    std::vector<int>& reference = numbers; 

    std::cout << reference[3]    << std::endl; 
    std::cout << referenceWrapper.get()[3] << std::endl; 
       // I need to use get^
       // otherwise does not compile. 
    return 0; 
} 

Se ho capito bene, la conversione implicita non si applica alle funzioni dei membri chiamanti. È una limitazione intrinseca? Devo usare lo std::reference_wrapper::get così spesso?

Un altro caso è questo:

#include <iostream> 
#include <functional> 

int main() 
{ 
    int a = 3; 
    int b = 4; 
    auto refa = std::ref(a); 
    auto refb = std::ref(b); 
    if (refa < refb) 
     std::cout << "success" << std::endl; 

    return 0; 
} 

Questo funziona bene, ma quando aggiungo questo sopra la definizione main:

template <typename T> 
bool operator < (T left, T right) 
{ 
    return left.someMember(); 
} 

Il compilatore tenta di creare un'istanza il modello e dimentica conversione implicita ed l'operatore integrato.

È questo comportamento inerente o sto fraintendendo qualcosa di cruciale sul std::reference_wrapper?

+3

'std :: reference_wrapper' ha alcuni usi molto specifici per gli autori di librerie, essendo rilevanti per l'inoltro e l'archiviazione perfetti degli argomenti (vedere ad esempio' std :: bind' e 'std :: thread'). Non consiglio di usarlo al di fuori di quelle situazioni. – Xeo

+8

'reference_wrapper' non sostituisce i riferimenti. –

+2

'modello bool operatore <(T sinistra, T destra) { return left.someMember(); } 'è un esempio di cosa MAI MAI MAI FARE MAI MAI quando sovraccarichi un operatore. Qualsiasi problema causato da quel codice non è il problema di nient'altro nella tua base di codice. (ok, forse in qualche spazio dei nomi ridicolmente ristretto e controllato da trovare tramite ADL, o simili altre situazioni inventate) – Yakk

risposta

28

Classe std::reference_wrapper<T> implementa un operatore implicita conversione in T&:

operator T&() const noexcept; 

e un getter più esplicito:

T& get() const noexcept; 

L'operatore implicita viene chiamato quando è richiesto un T (o T&). Per esempio

void f(some_type x); 
// ... 
std::reference_wrapper<some_type> x; 
some_type y = x; // the implicit operator is called 
f(x);   // the implicit operator is called and the result goes to f. 

Tuttavia, a volte un T non è necessariamente previsto e, in questo caso, è necessario utilizzare get. Ciò accade, soprattutto, in contesti di deduzione di tipo automatico. Per esempio,

template <typename U> 
g(U x); 
// ... 
std::reference_wrapper<some_type> x; 
auto y = x; // the type of y is std::reference_wrapper<some_type> 
g(x);  // U = std::reference_wrapper<some_type> 

Per ottenere some_type invece di std::reference_wrapper<some_type> sopra si dovrebbe fare

auto y = x.get(); // the type of y is some_type 
g(x.get());  // U = some_type 

Oppure l'ultima riga sopra potrebbe essere sostituito da g<some_type>(x);. Tuttavia, per gli operatori templatizzati (ad esempio ostream::operator <<()) credo che non sia possibile esplicitare il tipo.

+0

non sembra essere esplicito: http: //en.cppreference.com/w/cpp/utility/functional/reference_wrapper/get – xaxxon

+0

@xaxxon: era un errore di battitura e intendevo "implicito". Ho risolto il post. Grazie. –

Problemi correlati