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
?
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.
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.
The auto there works just the same. for(auto val : range) will always copy, for(auto& ref : range) will always be a reference.
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.
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 toT
; ifX
is a const iterator,reference
is a reference toconst 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.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With