1

For example:

#include <iostream>
#include <cstring>

using namespace std;

struct Square
{
    Square()
    {
        str = new char[10];
        strcpy(str, "Hello");
    }

    ~Square()
    {
        delete str;   
    }

    void print()
    {
        cout << "str = '" << str << "'" << endl;
    }

    char * str;    
};

class foo
{
public:
    typedef const Square & sqcref;
    typedef Square & sqref;
    foo(sqref && _ref)
    {
        fooStr = _ref.str;
        _ref.str = 0;
    }

    char * fooStr;
};

int main()
{
    Square s;
    s.print();
    foo f(s);
    s.print();
}

Output:

str = 'Hello'
str = '

Inside the constructor for foo, it expects an rvalue to a Square &, but what is passed in is a Square & lvalue. Why does this work?

Rollie
  • 4,391
  • 3
  • 33
  • 55
  • Are you sure the 2nd output is '? did you miss a '? – Gladaed May 29 '18 at 07:27
  • Strangely, that's what was output. Copy and paste this to http://cpp.sh/ c++14 version to repro. – Rollie May 29 '18 at 07:29
  • I think assigning a && reference like you did does not gurantee the validity of the original object. But more importantly what did you expect would happen? the output seems to match the code. – Gladaed May 29 '18 at 07:29
  • i just saw you used a char*. A 0 terminates it that might have thrown a monkey wrench into the output. Try what happens with other values. – Gladaed May 29 '18 at 07:30
  • I expect a compiler warning that there is no matching constructor, and in the closest candidate an lvalue can be assigned to an rvalue reference. – Rollie May 29 '18 at 07:31
  • Relevant: https://stackoverflow.com/questions/13725747/concise-explanation-of-reference-collapsing-rules-requested-1-a-a-2 – chris May 29 '18 at 07:31
  • Yes, if I cast it do `int *` before output, it outputs as you would expect. None of this is in any way related to the question though, so I don't know why it's important... – Rollie May 29 '18 at 07:31
  • The title is about `const` but the `const` typedef (`sqcref`) is not used. Is that a typo? (But then it wouldn't compile due to the assignment.) Is the `const` relevant or are you just asking about rvalue-lvalue reference collapsing as answered by @mpark? – drRobertz May 29 '18 at 09:15
  • @Gladaed, the reason the second `'` is not printed is that the program tries to print a `null` pointer (assigned in the foo constructor) as a C string. – drRobertz May 29 '18 at 09:16

2 Answers2

8

It works due to reference collapsing rules in C++11. Simply put, one cannot create reference to reference to value. So the 'references to references' collapse following below rules

Val && && -> Val &&

Val & && -> Val &

Val & & -> Val &

Val && & -> Val &

So in Your situation sqref && (which is Square & &&) collapses to Square &. So this is normal lvalue reference.

Community
  • 1
  • 1
bartop
  • 9,971
  • 1
  • 23
  • 54
  • 2
    Yeah, this makes sense. mpark beat you to the answer by 1 minute though - thanks all the same :) – Rollie May 29 '18 at 07:35
3

This is due to reference collapsing. sqref&& where sqref is T& collapses to T&.

https://wandbox.org/permlink/eWeYLdI3l0vSpNvo

mpark
  • 7,574
  • 2
  • 16
  • 18