In trying to compile the following code which would copy a map
s keys to a vector
:
map<string, string> mss;
vector<string> vs;
transform(mss.begin(), mss.end(), back_inserter(vs), get<0>);
VS2013 can't distinguish which get
is intended but this simpler usage works just fine:
vs.push_back(get<0>(*mss.begin()));
Specifying get<0, string, string>
didn't help. What am I missing?
There are many overloads of std::get
, where, in addition, each is a function template itself, therefore the compiler can't tell which one you want at the call site where you request for the address of one of them. If you insist on using std::get
, you'd need to use static_cast
:
transform(mss.begin(), mss.end(), back_inserter(vs),
static_cast<const map<string, string>::key_type&
(*)(map<string, string>::value_type&)>(std::get<0>)
);
Which will work as long as the type in static_cast
matches the declaration of a possible function template's specialization given as the argument. Also, you shoudn't try to explicitly specify the template arguments of function templates like get<0, string, string>
etc. - this is what the template argument deduction mechanism is for. Not only is the syntax ugly, but there can be other overloads added in the future breaking your compilation.
A much better alternative is to use a lambda expression:
transform(mss.begin(), mss.end(), back_inserter(vs),
[](map<string, string>::value_type& p){ return p.first; });
or a generic lambda expression (C++14):
transform(mss.begin(), mss.end(), back_inserter(vs),
[](auto& p){ return p.first; }); // or `return std::get<0>(p);`
or std::mem_fn
which binds its argument to a given pointer to a data member or a member function:
#include <functional>
transform(mss.begin(), mss.end(), back_inserter(vs),
mem_fn(&map<string, string>::value_type::first));
The first member of the pair stored in map is const-qualified. So technically you need
get<0, const string, string>
But that does not limit the list of candidates to one unambiguous overload, since get
is available in at least two versions: for const reference argument and for non-const reference argument.
You can choose one by using a cast
const string &(*g)(const pair<const string, string> &) =
get<0, const string, string>;
or
typedef map<string, string> Map;
const Map::key_type &(*g)(const Map::value_type &) =
get<0, const Map::key_type, Map::mapped_type>;
and then do
transform(mss.begin(), mss.end(), back_inserter(vs), g);
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