In C++, I'm using transform to change all the values of a map to uppercase.
std::map<std::string, std::string> data = getData();
// make all values uppercase
std::transform(data.begin(), data.end(), data.begin(),
[](std::pair<std::string, std::string>& p) {
boost::to_upper(p.second);
return(p);
});
This gives me the following compilation error:
/opt/local/include/gcc46/c++/bits/stl_algo.h:4805:2: error: no match for call to '(main(int, char**)::<lambda(std::pair<std::basic_string<char>, std::basic_string<char> >&)>) (std::pair<const std::basic_string<char>, std::basic_string<char> >&)
I think there's something wrong with the type of the argument in my lambda expression. It's probably something simple, but I can't seem to figure out what's expected.
STL Map Internal Implementation: It's implemented as a self-balancing red-black tree. Probably the two most common self balancing trees are red-black tree and AVL trees.
List: A list in STL is used to implement the doubly-linked lists. Unlike an array, lists are used to store the data, which is not contiguous.
Maps are part of the C++ STL (Standard Template Library). Maps are the associative containers that store sorted key-value pair, in which each key is unique and it can be inserted or deleted but cannot be altered. Values associated with keys can be changed.
The transform() function in C++ sequentially applies an operation to the elements of an array(s) and then stores the result in another output array. The transform function is used in two forms: Unary operation: The operation is applied to each element in the input range, and the result is stored in the output array.
You are missing the const in the first type of the pair.
[](std::pair<const std::string, std::string>& p) {
However this is not your problem: You cannot use a map
as the OutputIterator, as they do not support assignment. You can, however mutate the second argument using std::for_each
.
Good old map_to_foobar
:
std::for_each(data.begin(), data.end(),
[](std::pair<const std::string, std::string>& p) {
p.second = "foobar";
});
Conceptual stuff: Calling transform
with the same range as input and output is quite legit and makes a lot of sense if all your functors return by value and don't mutate their arguments. However, mutating something in place can be a faster (or at least look faster in code, nevermind the optimizing compiler) and makes a lot of sense with member functions.
If you plan on sticking to std::transform
, then you need std::inserter()
:
C++03 MCVE
typedef std::map<int, std::string> Map;
struct ToUpper
{
Map::value_type & operator()(Map::value_type & pair) const
{
boost::to_upper(pair.second);
return pair;
}
};
int main()
{
Map m;
m[0] = "snake_case";
m[1] = "camelCase";
m[2] = "PascalCase";
std::transform(m.begin(), m.end(), std::inserter(m, m.end()), ToUpper());
for (Map::const_iterator it = m.begin(); it != m.end(); ++it)
std::cout << it->first << ", " << it->second << std::endl;
}
C++11 (you can do everything in main()
really)
int main()
{
auto m = getData();
auto toUpper = [] (decltype(m)::value_type & pair)
{
boost::to_upper(pair.second);
return pair;
};
std::transform(m.begin(), m.end(), std::inserter(m, m.end()), toUpper);
for (auto const & pair : m)
std::cout << pair.first << ", " << pair.second << std::endl;
}
C++14 (you can use auto
in lambda parameters)
int main()
{
auto m = getData();
auto toUpper = [] (auto & pair)
{
boost::to_upper(pair.second);
return pair;
};
std::transform(m.begin(), m.end(), std::inserter(m, m.end()), toUpper);
for (auto const & pair : m)
std::cout << pair.first << ", " << pair.second << std::endl;
}
C++17 (just because i love structured bindings)
int main()
{
auto m = getData();
auto toUpper = [] (auto & pair)
{
boost::to_upper(pair.second);
return pair;
};
std::transform(m.begin(), m.end(), std::inserter(m, m.end()), toUpper);
for (auto const & [key, value] : m)
std::cout << key << ", " << value << std::endl;
}
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