What is the difference between std::pair with references and reference wrappers

757 Views Asked by At

I've fallen over a bad assumption that I made. I discovered that

std::pair<int &, int &>

is a thing. However I didn't expect the following to fail

int a = 10;
int b = 20;
int c = 30;

using PRef = std::pair<int &, int &>;

PRef p0 = {a,b};
PRef p1 = {b,c};


EXPECT_EQ(a, 10);
EXPECT_EQ(b, 20);
EXPECT_EQ(c, 30);

p0 = p1;

EXPECT_EQ(a, 10);
EXPECT_EQ(b, 20);
EXPECT_EQ(c, 30);

However the second set of tests after the assignment fails because

a is 20 # copied from b
b is 30 # copied from c

I kind of expected this to behave like reference wrapper where the underlying pointer would get copied but this is not how it seems to work. Is there some clear reasoning why the behaviour is different to using

std::pair<std::reference_wrapper<int>, std::reference_wrapper<int>>

If I run the same test as above but with reference_wrapper then it works.

{
        int a = 10;
        int b = 20;
        int c = 30;

        using PRef = std::pair<std::reference_wrapper<int> , std::reference_wrapper<int>>;

        PRef p0 = {std::ref(a),std::ref(b)};
        PRef p1 = {std::ref(b),std::ref(c)};


        EXPECT_EQ(a, 10);
        EXPECT_EQ(b, 20);
        EXPECT_EQ(c, 30);

        p0 = p1;

        EXPECT_EQ(a, 10);
        EXPECT_EQ(b, 20);
        EXPECT_EQ(c, 30);


    }

Is there supposed to be a difference between the two forms?

1

There are 1 best solutions below

1
On

It has this behavior for the same reason that

int a = 10;
int b = 20;

int &aref = a;
int &bref = b;

aref = bref;

Assigns a to b. Real references (as opposed to reference wrappers) can't be rebound. Assigning to a reference calls the assignment operator on what it's referencing.

std::reference_wrapper::operator= rebinds the reference. So if aref and bref were std::reference_wrappers the assignment wouldn't change a.