When running a range-based for loop on an std::unordered_map it appears that the type of the loop variable does not use reference types:
std::unordered_map<int, int> map = { {0, 1}, {1, 2}, {2, 3} };
for(auto&[l, r] : map)
static_assert(std::is_same_v<decltype(r), int&>);
MSVC 2017, gcc 8.2 and clang 7.0.0 all report a failed assertion here. Oppose this to a std::vector, where the assertion does not fail, as one would expect:
std::vector<int> vec = { 1, 2, 3 };
for(auto& r : vec)
static_assert(std::is_same_v<decltype(r), int&>);
However on both MSVC 2017 and gcc 8.2 a loop modifying the local variable r will have observable side-effects:
#include <iostream>
#include <type_traits>
#include <unordered_map>
#include <vector>
int main() {
std::unordered_map<int, int> a = { {0, 1}, {1, 2}, {2, 3} };
for(auto[l, r] : a)
std::cout << l << "; " << r << std::endl;
for(auto&[l, r] : a) {
static_assert(std::is_same_v<decltype(r), int>);
r++;
}
std::cout << "Increment:" << std::endl;
for(auto[l, r] : a)
std::cout << l << "; " << r << std::endl;
}
This program for example will print (ignoring order):
0; 1
1; 2
2; 3
Increment:
0; 2
1; 3
2; 4
What am I missing? How can this change the value in the map despite the local variable not being of reference type? Or probably more appropriately, why does std::is_same not see the right type, because quite clearly it is a reference type? Or am I alternatively missing some undefined behavior?
Note that I did reproduce the same issue without using structured bindings, so I keep the nice looking code here. See here for an example