C++11 "auto" semantics

C++C++11

C++ Problem Overview


When I use C++11 auto, what are the rules of type deduction with regards to whether it will resolve to a value or a reference?

E.g, sometimes it is clear:

auto i = v.begin(); // Copy, begin() returns an iterator by value

These are less clear:

const std::shared_ptr<Foo>& get_foo();
auto p = get_foo(); // Copy or reference?

static std::shared_ptr<Foo> s_foo;
auto sp = s_foo; // Copy or reference?

std::vector<std::shared_ptr<Foo>> c;
for (auto foo: c) { // Copy for every loop iteration?

C++ Solutions


Solution 1 - C++

The rule is simple : it is how you declare it.

int i = 5;
auto a1 = i;    // value
auto & a2 = i;  // reference

Next example proves it :

#include <typeinfo>
#include <iostream>    

template< typename T >
struct A
{
	static void foo(){ std::cout<< "value" << std::endl; }
};
template< typename T >
struct A< T&>
{
	static void foo(){ std::cout<< "reference" << std::endl; }
};

float& bar()
{
	static float t=5.5;
	return t;
}

int main()
{
	int i = 5;
	int &r = i;

	auto a1 = i;
	auto a2 = r;
	auto a3 = bar();

	A<decltype(i)>::foo();       // value
	A<decltype(r)>::foo();       // reference
	A<decltype(a1)>::foo();      // value
	A<decltype(a2)>::foo();      // value
	A<decltype(bar())>::foo();   // reference
	A<decltype(a3)>::foo();      // value
}

The output:

value
reference
value
value
reference
value

Solution 2 - C++

§7.1.6.4 [dcl.spec.auto] p6 > 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.

This means nothing else than that auto models template argument deduction during a function call.

template<class T>
void f(T){} // #1, will also be by-value

template<class T>
void g(T&){} // #2, will always be by-reference

Note that #1 will always copy the passed argument, no matter if you pass a reference or anything else. (Unless you specifically specify the template argument like f<int&>(intref);.)

Solution 3 - C++

Whatever you get from right side ( of "=" ) is never a reference. More specifically the result of an expression is never a reference. In this light, note the difference between results in the example.

#include <typeinfo>
#include <iostream>

template< typename T >
struct A
{
    static void foo(){ std::cout<< "value" << std::endl; }
};

template< typename T >
struct A< T&>
{
    static void foo(){ std::cout<< "reference" << std::endl; }
};

float& bar()
{
    static float t=5.5;
    return t;
}

int main()
{
   auto a3 = bar();

   A<decltype(bar())>::foo(); // reference
   A<decltype(a3)>::foo();    // value
}
 

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlex BView Question on Stackoverflow
Solution 1 - C++BЈовићView Answer on Stackoverflow
Solution 2 - C++XeoView Answer on Stackoverflow
Solution 3 - C++qqqqqView Answer on Stackoverflow