0

I'm not sure how the auto keyword works. Here is an illustration of my issue:

class Element {
  public:
    void setA(int a) {
      m_a = a;
    }

    int& a() {
      return m_a;
    }

  private:
    int m_a = 0;
};


int main(int argc, char* argv[])
{
  Element el;

  auto a = el.a();
  a = 2;
  // displays 2, 0
  std::cout << a << ", " << el.a() << std::endl;

  int& b = el.a();
  b = 3;
  // displays 3, 3
  std::cout << b << ", " << el.a() << std::endl;

  return 0;
}

In my understanding, auto deduce the declaration type from the context in which it is used. Here, it should deduce the a variable as being a reference to an integer since Element:a() is declared as a method returning a reference to an integer.

Instead, it seems that the a variable is a copy of the m_a attribute of the Element class.

I found that I needed to specify auto& to get a reference to the attribute. But I don't really understand why I need to add the ampersand. Shouldn't the compiler know that if a is initialized from a method returning a reference, then it should also be a reference ?

Nicolas Appriou
  • 2,208
  • 19
  • 32
  • You need to use `auto&` for a reference. – drescherjm Jun 11 '20 at 17:37
  • If the rule was like you suggested, then how would you make a *copy* of the reference returned by `a`? – cigien Jun 11 '20 at 17:37
  • If you want a reference, you need to add the `&`. Otherwise you are making a copy into a new object. (If the syntax was reversed, and `auto` would make a reference to a returned reference, what would be the syntax of `auto` to not make a reference? Maybe `auto!&`? – Eljay Jun 11 '20 at 17:38

1 Answers1

0

Shouldn't the compiler know that if a is initialized from a method returning a reference, then it should also be a reference ?

It could, but that's not how C++ works.

The expression el.a() is an lvalue int, not a reference. The expression refers to the original object, but the reference qualifier has been dropped by this point. It's complicated and confusing but that's just how C++ works. Consequently, it's also how auto works.

You'll have to write auto& to get a new reference. A bonus of this is that there is syntax to get a copy, which there wouldn't be otherwise.

It's the same as why the expression std::move(aThing) is an rvalue of type T, not of type T&&, even though std::move is literally a cast to T&&.

Asteroids With Wings
  • 17,071
  • 2
  • 21
  • 35
  • Thanks for the quick response. Do you have any link to some resource where I could learn more about it ? I didn't really knew what to search for when working on this by myself. – Nicolas Appriou Jun 11 '20 at 17:41
  • @NicolasAppriou Sorry, I don't know which (if any) books go into this level of detail. The "why" of C++ is quite involved. Perhaps somebody else has a suggestion though. – Asteroids With Wings Jun 11 '20 at 17:42