Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

`auto` specifier type deduction for references

Let's consider the following code snippet

void Test()
  {
  int x = 0;

  int& rx = x;
  int* px = &x;

  auto apx = px;    // deduced type is int*
  auto arx = rx;    // deduced type is int
  }

One could draw an analogy from pointer types expecting that the deduced type of arx is int&, but it is int in fact.

What is the rule in Standard which governs that? What is the reason behind it? Sometimes I get caught by it in a case like this:

const BigClass& GetBigClass();
...
auto ref_bigclass = GetBigClass();   // unexpected copy is performed
like image 257
Andrey Avatar asked Aug 09 '12 15:08

Andrey


2 Answers

Use auto&:

auto& ref_bigclass = GetBigClass();

References are supposed to be transparent: any operation on them happens on the object they refer to, there is no way to 'get' reference itself.

UPD: This is covered in 7.1.6.4/6:

Once the type of a declarator-id has been determined according to 8.3, the type of the declared variable using the declarator-id is determined from the type of its initializer using the rules for template argument deduction.

And template argument deduction is defined in 14.8.2.1/3:

If template parameter type P is a reference type, the type referred to by P is used for type deduction.

P.S. Note that this is different for decltype: decltype(rx) will yield int& type (7.1.6.2/4).

like image 92
hamstergene Avatar answered Sep 23 '22 18:09

hamstergene


The simplest way to think about it is comparing it to template argument deduction.

Given:

template<typename T>
void deduce(T) { }

If you call:

deduce(px);

then the template argument T will be deduced as int* and if you call

deduce(rx);

then T will be deduced as int, not int&

You get the same types deduced when using auto.

One could draw an analogy from pointer types expecting that the deduced type of arx is int&

You'd have to have a fairly confused model of the C++ language to make that analogy. Just because they are declared in syntactically similar ways, as Type@ with a type and a modifier doesn't make them work the same way. A pointer is a value, an object, and it can be copied and have its value altered by assignment. A reference is not an object, it's a reference to some object. A reference can't be copied (copying it copies the referent) or altered (assigning to it alters the referent). A function that returns a pointer returns an object by value (the object in question being a pointer object), but a function that returns a reference (like your GetBigClass()) returns an object by reference. They're completely different semantics, trying to draw analogies between pointers and references is doomed to failure.

like image 44
Jonathan Wakely Avatar answered Sep 19 '22 18:09

Jonathan Wakely