Ist dieses Verhalten von std :: ref logisch?

68

Betrachten Sie diesen Code:

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

Bei Ausführung wird dieser Code ausgegeben

107
100

Ich hätte erwartet, dass der zweite Wert 7 statt 100 ist.

Was vermisse ich?

oz1cz
quelle
17
Der Referenz-Wrapper kann erneut eingesetzt werden, sodass Änderungen zugewiesen werden, auf die verwiesen wird, nicht auf das referenzierte Objekt.
Kerrek SB

Antworten:

57

Eine kleine Modifikation f2liefert den Hinweis:

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

Dies macht jetzt, was Sie erwarten.

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

Es wird keine Zuordnung zur umschlossenen Referenz vorgenommen.

In diesem f1Fall funktioniert alles wie erwartet, da a std::reference_wrapper<T>einen Konvertierungsoperator für bereitstellt T&, der an die implizite rechte Seite von ints implizit bindet operator+.

Richard Hodges
quelle
1
Benötigen Sie einen Job?
Ramy
12

reference_wrapperhat operator =und einen nicht expliziten Konstruktor, siehe Dokumentation .

Auch wenn es überraschend ist, ist es das normale Verhalten:

f2bindet den lokalen reference_wrapper erneut an xx.

Jarod42
quelle
10

arg = xx;

Lokal argbezieht sich jetzt auf (gelesen als Bindungen mit) xx. (Und nicht mehr bezieht sich auf j)

arg += xx;

Implizit operator T& ()wird angewendet, um mit dem Argument von operator +=übereinzustimmen, und daher wird die Addition für das referenzierte Objekt durchgeführt, d j. H.

Das beobachtete Verhalten ist also korrekt.

Mohit Jain
quelle