Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does auto deduce type?

Tags:

c++

c++11

I have some cases of use of auto:

auto s = expr;          //s is always lvalue
auto & s = expr;        //s is always lvalue reference? What if expr is rvalue?
auto && s = expr;       //s is perfectly forwarded

Are they true? If not, why?

like image 770
SwiftMango Avatar asked Jan 12 '14 01:01

SwiftMango


People also ask

How does auto keyword work?

1) auto keyword: The auto keyword specifies that the type of the variable that is being declared will be automatically deducted from its initializer. In the case of functions, if their return type is auto then that will be evaluated by return type expression at runtime.

Can a car deduce a pointer?

C++ static code analysis: "auto" should not be used to deduce raw pointers.

How does C++ auto work?

The auto keyword in C++ automatically detects and assigns a data type to the variable with which it is used. The compiler analyses the variable's data type by looking at its initialization. It is necessary to initialize the variable when declaring it using the auto keyword.

Why auto keyword is used in C++?

The auto keyword specifies that the type of the variable that is begin declared will automatically be deduced from its initializer and for functions if their return type is auto then that will be evaluated by return type expression at runtime.


1 Answers

dyp is correct and I would like to elaborate.

First of all, the conclusion is the from dyp:

The type deduced for auto in the declaration of a variable is defined via the rules of template argument deduction, see [dcl.spec.auto]/6; with one exception: if the initializer is a braced-init-list, the deduced type is a std::initializer_list.

I'll explain.

First,

auto s = expr;

This is same as deducing the T from expr,

template<class T>
void f(T s);

f(expr);

The rule for template argument deduction is quite complicated, since you are only concerning with the lvalue and rvalue stuff, let's focus on this.

Template argument deduction is by comparing the template parameter type (call it P, in this case P is T), and the corresponding argument (call it A, in this case, the type of expr).

From 14.8.2.1,

If P is not a reference type:

— If A is an array type, the pointer type produced by the array-to-pointer standard conversion (4.2) is used in place of A for type deduction; otherwise,

— If A is a function type, the pointer type produced by the function-to-pointer standard conversion (4.3) is used in place of A for type deduction; otherwise,

— If A is a cv-qualified type, the top level cv-qualifiers of A’s type are ignored for type deduction.

So, if expr is array or function, it will be treated as pointers, if expr has cv-qualification (const etc), they will be ignored.

If P is a cv-qualified type, the top level cv-qualifiers of P’s type are ignored for type deduction.

This actually says:

const auto s = expr;

s is a const variable, but for type deduction for auto purposes, the const will be removed.

Thus, from the above rules, auto will be deduced to the type of expr (after some type conversion stated above).

Note that, when an expression is a reference to T, it will be adjusted to T before prior analysis.

So whatever expr is – rvalue, lvalue, or lvalue/rvalue ref type – the type of auto will always be the type of expr without reference.

auto s1 = 1; //int
int &x = s1;
auto s2 = x; //int
int &&y = 2;
auto s3 = y; //int

Second, let's look at

auto &s = expr;

This will be same as

template<class T>
void f(T &s);

f(expr);

The extra rule from standard is as follows:

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

So the deduction of auto will be exactly same as without &, but after the auto type is deducted, the & is added to the end of auto.

//auto &s1 = 1; //auto is deducted to int, int &s1 = 1, error!
const auto &s1 = 1; //auto is deducted to int, const int &s1 = 1; ok!
const int &x = s1;
auto &s2 = x; //auto is int, int &s2 = x; ok!
int &&y = 2;
auto &s3 = y; //auto is int, int &s3 = y; ok! 

Note that the last y is an lvalue. The rule of C++ is: named rvalue reference is an lvalue.

Lastly:

auto &&s = expr;

This is no doubt same as

template<class T>
void f(T &&s);

f(expr);

One additional rule from standard:

If P is an rvalue reference to a cv-unqualified template parameter and the argument is an lvalue, the type “lvalue reference to A” is used in place of A for type deduction.

This actually says that, if expr is an rvalue, the rule will be same as the second case (lvalue case), but if expr is an lvalue, the type of A will be an lvalue reference to A.

Note from previous explained, A is never reference, because the type of an expression is never a reference. But for this special case (auto &&, and A is an lvalue), reference to A must be used, regardless expr itself is a reference type or not.

Example:

auto &&s1 = 1; //auto is deducted to int, int &&s1 = 1, ok!
int x = 1;
auto &&s2 = x; //x is lvalue, so A is int &, auto is deducted to int &, int & &&s2 = x; ok!
int &&y = 2;
auto &&s3 = y; //y is lvalue, auto is int &, int & &&s3 = y; ok!
like image 145
user534498 Avatar answered Oct 04 '22 17:10

user534498