Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type of auto reference

If I have the following two loops:

std::vector<int> v;

for(auto i : v)
  //do something with i

for(auto& j : v)
  //do something with j

When I hover over i, intellisense shows it as int i (as expected). However, when I hover over j I don't get int& as I expected to, but rather

std::_Simple_types<std::_Wrap_alloc<std::_Vec_base_types<int, std::allocator<int> >::_Alloc>::value_type>::value_type &j

What is this complicated definition? Is it the same as int&? If not, what is it? And if it is, why can it deduce just int for i, but not int& for j?

like image 375
Baruch Avatar asked Jun 05 '14 11:06

Baruch


People also ask

Is Auto a reference?

The auto keyword by itself represents a value type, similar to int or char . It can be modified with the const keyword and the & symbol to represent a const type or a reference type, respectively. These modifiers can be combined.

What data type is auto?

As explained above, the auto keyword in C++ detects the data type of a variable by itself. This means that we can replace the data type of a variable with the keyword auto in C++. The compiler will automatically detect the variable's data type at compile time.

Will auto be a reference C++?

The auto there works just the same. for(auto val : range) will always copy, for(auto& ref : range) will always be a reference.

What is the difference between auto and decltype?

auto is a keyword in C++11 and later that is used for automatic type deduction. The decltype type specifier yields the type of a specified expression. Unlike auto that deduces types based on values being assigned to the variable, decltype deduces the type from an expression passed to it.


2 Answers

The standard states in 6.5.4 [stmt.ranges]:

For a range-based for statement of the form

for ( for-range-declaration : expression ) statement

let range-init be equivalent to the expression surrounded by parentheses

( expression )

In each case, a range-based for statement is equivalent to

{
    auto && __range = range-init;
    for ( auto __begin = begin-expr,  __end = end-expr;  __begin != __end; ++__begin ) {
        for-range-declaration = *__begin;
        statement
    }
}

So you can see that in your case the types of i and j are deduced from the type of *it where it is a std::vector iterator. std::vector iterators are implementation defined, however the result of *it is not.


As indicated in the comments, a std::vector iterator is a forward iterator, and after 24.2.5/1 [forward.iterators]:

A class or pointer type X satisfies the requirements of a forward iterator if

  • ...
  • if X is a mutable iterator, reference is a reference to T; if X is a const iterator, reference is a reference to const T,

Here reference is used in 24.4.4/2 [iterator.iterators] to indicate the return type of *it.


Thus for your case the standard requires the type of i to be int and the type of j to be int&. This is probably the case for MSVC++, and intellisense is just not able to correctly resolve the type.


Edit: Fixed the answer regarding the return type when dereferencing iterators.

like image 141
Danvil Avatar answered Oct 11 '22 04:10

Danvil


IntelliSense is giving you a peek into the implementation of std::vector. That is a complicated way of saying reference to std::vector<int>::value_type or, in this case, reference to int.

like image 32
Blastfurnace Avatar answered Oct 11 '22 05:10

Blastfurnace