2016-05-08 9 views
66

Considerate questo codice:Questo comportamento std :: ref è logico?

#include <iostream> 
#include <functional> 

int xx = 7; 

template<class T> 
void f1(T arg) 
{ 
    arg += xx; 
} 

template<class T> 
void f2(T arg) 
{ 
    arg = xx; 
} 

int main() 
{ 
    int j; 

    j=100; 
    f1(std::ref(j)); 
    std::cout << j << std::endl; 

    j=100; 
    f2(std::ref(j)); 
    std::cout << j << std::endl; 
} 

Quando viene eseguito, uscite questo codice

107 
100 

mi sarei aspettato il secondo valore di essere 7 invece di 100.

Che cosa mi manca?

+16

Il wrapper di riferimento è resettabile, quindi assegnando le modifiche a ciò che viene fatto riferimento, non l'oggetto di riferimento. –

+1

Ottima domanda! – vsoftco

risposta

56

Una piccola modifica al f2 fornisce l'indizio:

template<class T> 
void f2(T arg) 
{ 
    arg.get() = xx; 
} 

Questo fa ora ciò che vi aspettate.

Questo è accaduto perché std::ref restituisce un oggetto std::reference_wrapper<>. L'operatore di assegnazione di cui rebinds il wrapper. (vedere http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper/operator%3D)

Non esegue un'assegnazione al riferimento spostato.

Nel caso f1, tutto funziona come previsto a causa di un std::reference_wrapper<T> fornisce un operatore di conversione a T&, che legherà al lato implicita destro della int s implicita operator+.

+1

Hai bisogno di un lavoro? – Ramy

+0

Ok, grazie molte – Ramy

11

reference_wrapper ha operator = e un costruttore non esplicito, vedere documentation.

Quindi, anche se è sorprendente, è il comportamento normale:

f2 rebinds il reference_wrapper locale per xx.

8

arg = xx;

locale arg ora si riferisce a (letto come si lega con) xx. (E non più si riferisce a j)

arg += xx;

implicito operator T&() viene applicata per abbinare l'argomento della operator += e quindi aggiunta viene eseguita su oggetto cui cioè j.

Quindi il comportamento osservato è corretto.