Why does assigning std::ref not change the value of the referenced object?
Asked Answered
S

3

70

Consider this 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;
}

When executed, this code outputs

107
100

I would have expected the second value to be 7 rather than 100.

What am I missing?

Shanaeshanahan answered 8/5, 2016 at 15:8 Comment(1)
The reference wrapper is reseatable, so assigning changes what's referenced, not the referred object.Candiscandle
S
58

A small modification to f2 provides the clue:

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

This now does what you expect.

This has happened because std::ref returns a std::reference_wrapper<> object. The assignment operator of which rebinds the wrapper. (see http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper/operator%3D)

It does not make an assignment to the wrapped reference.

In the f1 case, all is working as you expected because a std::reference_wrapper<T> provides a conversion operator to T&, which will bind to the implicit right hand side of ints implicit operator+.

Sickert answered 8/5, 2016 at 15:15 Comment(1)
Do you need a job ?Burweed
T
12

reference_wrapper has operator = and a non explicit constructor, see documentation.

So, even if it is surprising, it is the normal behaviour:

f2 rebinds the local reference_wrapper to xx.

Tillich answered 8/5, 2016 at 15:17 Comment(0)
C
11

arg = xx;

Local arg now refers to (read as binds with) xx. (And no more refers to j)

arg += xx;

Implicit operator T& () is applied to match the argument of operator += and hence addition is performed on referred object i.e. j.

So the observed behaviour is correct.

Cowie answered 9/5, 2016 at 6:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.