2016-05-08 13 views
66

Betrachten Sie diesen Code:Ist das Verhalten von std :: ref logisch?

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

Wenn er ausgeführt wird, dieser Code Ausgänge

107 
100 

I der zweite Wert 7 erwartet hätte lieber zu sein als 100.

Was bin ich?

+16

Der Referenzwrapper ist wiedersetzbar, so dass die Zuweisung ändert, was referenziert wird, nicht das referenzierte Objekt. –

+1

Ausgezeichnete Frage! – vsoftco

Antwort

56

Eine kleine Änderung f2 liefert den Hinweis:

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

Das jetzt tut, was Sie erwarten.

Dies ist passiert, weil std::ref ein Objekt std::reference_wrapper<> zurückgibt. Der Zuweisungsoperator bindet den Wrapper. (siehe http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper/operator%3D)

Es wird keine Zuordnung zu der umschlossenen Referenz vorgenommen.

Im f1 Fall alles funktioniert wie erwartet, weil ein std::reference_wrapper<T> einen Umwandlungsoperator zu T& bietet, die auf die implizite rechten Seite der int impliziten operator+ binden.

+1

Brauchen Sie einen Job? – Ramy

+0

Okay, vielen Dank – Ramy

11

reference_wrapper hat operator = und einen nicht expliziten Konstruktor, siehe documentation.

Also, auch wenn es überraschend ist, ist es das normale Verhalten:

f2 erneut bindet den lokalen reference_wrapper zu xx.

8

arg = xx;

Lokale arg bezieht sich jetzt auf (lesen wie bei bindet) xx. (Und nicht mehr bezieht sich auf j)

arg += xx;

Implicit operator T&() wird angewendet, um das Argument der operator += und somit zusätzlich passen auf genannte Objekt durchgeführt wird, das heißt j.

So ist das beobachtete Verhalten korrekt.

Verwandte Themen