2

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?

bradgonesurfing
  • 30,949
  • 17
  • 114
  • 217
  • 2
    Note that `operator=` for `reference_wrapper` rebinds it: https://en.cppreference.com/w/cpp/utility/functional/reference_wrapper/operator%3D. – Daniel Langr Sep 17 '20 at 15:26
  • 2
    [std::reference_wrapper is rebindable](https://en.cppreference.com/w/cpp/utility/functional/reference_wrapper/operator%3D), unlike references. I think this question and appropriate answers would be the same if `std::pair` were not even mentioned. – Drew Dormann Sep 17 '20 at 15:26
  • @DanielLangr That looks like an answer. – cigien Sep 17 '20 at 15:27
  • @cigien Don't have time yet to write it in the context of the question. Anyone is free to do that, please. – Daniel Langr Sep 17 '20 at 15:28
  • 1
    Not sure this is really a duplicate. The answered question is relevant since it talks about the behavior of reference assignments, but it doesn't address the different behavior of `std::reference_wrapper` which is what this question is about. – Nathan Pierson Sep 17 '20 at 16:11

1 Answers1

3

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.

Kevin
  • 6,993
  • 1
  • 15
  • 24