Reputation: 517
EDIT: The answer to the first question is to use std::pair. Any ideas about the second one (marked as 'bonus question')?
With the following code:
#include <map>
#include <vector>
void foo(std::pair<int, int>& p) // EDIT: it needs to be non-const
{}
int main()
{
std::pair<int, int> p{1,2};
foo(p);
std::vector<std::pair<int, int>> v{{1,2}};
for (auto& element : v)
{
foo(element); // works fine
}
std::map<int, int> m{std::make_pair(1,2)};
//std::map<int, int> m2{{1,2}};
for (auto& element : m) // the problematic loop
{
foo(element);
}
return 0;
}
I get the following message with m in the latter for loop:
error: invalid initialization of reference of type 'std::pair&' from expression of type 'std::pair'
and the following with m2 in that place:
error: invalid initialization of non-const reference of type 'std::pair&' from an rvalue of type 'std::pair'
Why is that?
Bonus question: I find it very peculiar that when the initialization of m2 is not commented out and the for loop stays untouched (there's still m in it and m2 is never used) the error message changes from
error: invalid initialization of reference of type 'std::pair&' from expression of type 'std::pair'
to
error: invalid initialization of non-const reference of type 'std::pair&' from an rvalue of type 'std::pair'
I'd love to know your thoughts about it. I tested this code with onlinegdb.com
Upvotes: 0
Views: 844
Reputation: 1322
You're not allowed to modify the keys of the map, hence this works:
#include <map>
#include <vector>
// foo can modify the first value of the pair
void foo(std::pair<int, int>& p)
{}
// fooConstFirst cannot modify the first value of the pair
void fooConstFirst(std::pair<const int, int>& p)
{}
int main()
{
std::pair<int, int> p{1,2};
foo(p);
std::vector<std::pair<int, int>> v{{1,2}};
for (auto& element : v)
{
foo(element);
}
std::map<int, int> m{std::make_pair(1,2)};
for (auto& element : m)
{
fooConstFirst(element);
}
return 0;
}
Upvotes: 3
Reputation: 67733
Per the documentation,
map::value_type = std::pair<const Key, T>
meaning
map<int,int>::value_type = pair<const int, int>
So the compiler can implicitly convert your element of type pair<const int,int>&
to a temporary (rvalue) of type pair<int,int>
, but this can't be passed by non-const ref to the function.
Either change the argument type to pair<const int,int>
, or take it by value.
For reference, gcc 6.3 provided this very informative error:
prog.cpp: In function ‘int main()’:
prog.cpp:21:13: error: invalid initialization of non-const reference of type ‘std::pair<int, int>&’ from an rvalue of type ‘std::pair<int, int>’
foo(element);
^~~~~~~
In file included from /usr/include/c++/6/bits/stl_algobase.h:64:0,
from /usr/include/c++/6/bits/stl_tree.h:63,
from /usr/include/c++/6/map:60,
from prog.cpp:1:
/usr/include/c++/6/bits/stl_pair.h:272:19: note: after user-defined conversion: constexpr std::pair<_T1, _T2>::pair(const std::pair<_U1, _U2>&) [with _U1 = const int; _U2 = int; typename std::enable_if<(std::_PCC<((! std::is_same<_T1, _U1>::value) || (! std::is_same<_T2, _U2>::value)), _T1, _T2>::_ConstructiblePair<_U1, _U2>() && std::_PCC<((! std::is_same<_T1, _U1>::value) || (! std::is_same<_T2, _U2>::value)), _T1, _T2>::_ImplicitlyConvertiblePair<_U1, _U2>()), bool>::type <anonymous> = 1u; _T1 = int; _T2 = int]
constexpr pair(const pair<_U1, _U2>& __p)
^~~~
prog.cpp:4:6: note: initializing argument 1 of ‘void foo(std::pair<int, int>&)’
void foo(std::pair<int, int>& p)
Note particularly the strong clue about after user-defined conversion...
Upvotes: 4
Reputation: 136266
The container makes the key const
(this applies to all associative containers):
value_type std::pair<const Key, T>
So it should be void foo(std::pair<int const, int>& p)
.
Upvotes: 6