I'm trying to print the second member variable of all items in an stl map using a lambda expression
map<int, int> theMap;
for_each(theMap.begin(), theMap.end(),
cout << bind(&pair<int, int>::second, _1) << constant(" "));
but this is not compiling. I essentially want to de-reference the placeholder. Any idea what I'm missing here?
Thanks in advance!
Try:
for_each(theMap.begin(), theMap.end(),
cout << bind(&map<int, int>::value_type::second, _1) << constant(" "));
std::map will add const to its key; this is to prevent messing up the ordering. Your pair should be:
std::pair<const int, int>
Like dirkgently suggests, use the value_type to always get the correct type. The verbosity is alleviated with a typedef:
typedef std::map<int, int> int_map;
int_map::value_type::second
Related
I am using map to store elements and I need to allocate a dynamic map memory such that I can pass this memory to caller function without any hassle however the following code snippet is confusing me. Have a look here.
std :: map <int, int> map1;
map1[some_integer_x] = some_integer_y; // OK at compilation.
But following snippet is not OK and gives error.
std :: map <int, int> * map2 = new std :: map <int, int>
map2[some_integer_x] = some_integer_y; // Not OK at compilation.
Here is the error it gives me on GCC 5.
error: no match for ‘operator=’ (operand types are ‘std::map<int, int>’ and ‘int’)
map2[some_integer_x] = some_integer_y;
I can understand that this is related to some pointers issue. What can be reason? What are my other options? I want to pass map without involving a copy as map will contain huge amount of information.
map2 is a pointer to map.
To access the std::map::operator[] you need to dereference the pointer first, using the operator *.
Because [] has higher operator precedence than *, you need to write
(*map2)[some_integer_x] = some_integer_y;
Since map2 is a pointer, then operator[] works the same way as for an array of std::map<int, int>.
The line :
map2[some_integer_x] = some_integer_y;
Means "go to the element some_integer_x and assign the to it value some_integer_y".
That causes the compilation error of mismatched type, because
type of map2[some_integer_x] is std::map<int, int> you are trying to assign an integer value to it.
So, the first of all you need to deference the pointer:
(*map2)[some_integer_x] = some_integer_y;
You are operating on the pointer to a map as if it were an instance of a map. You need to dereference the pointer before use like in the example below:
#include <map>
#include <iostream>
int main() {
std :: map <int, int> map1;
map1[1] = 2;
std::map<int, int> *map2 = new std::map<int, int>();
(*map2)[1] = 3;
std::cout << "Map1 at location 1 is: " << map1[1] << std::endl; //Prints 2
std::cout << "Map2 at location 1 is: " << (*map2)[1] << std::endl; // Prints 3
delete map2;
}
I try to print only a struct member from vector of my struct (struct pnt). let me be clear by showing this:
struct pnt {
char _name;
int _type;
bool _aux;
};
boost::copy(pntVec.begin(),pntVec.end()|
boost::adaptors::transformed(bind(&pnt::_type, _1)),
std::ostream_iterator<int>(std::cout, "\n"));
but I get an error. I will appreciate if you could please help me to find the reason for that.
Error:
error: no type named ‘type’ in ‘boost::mpl::eval_if_c<true, boost::range_const_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> >, void>, boost::range_mutable_iterator<const __gnu_cxx::__normal_iterator<int*, std::vector<int> >, void> >::f_ {aka struct boost::range_const_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> >, void>}’
NOTE: I can olny use C++98, boost v.1.56
Boost Adaptor adapts ranges, not single iterators. Similarily, the boost::copy algorithm expects two arguments, where the first one is a range, and the second an output iterator. Having said that, the correct syntax for extracting a single data member from a range, and copying it to an output iterator is:
boost::copy(pntVec | boost::adaptors::transformed(bind(&pnt::_type, _1))
, std::ostream_iterator<int>(std::cout, "\n"));
Alternatively, since Phoenix in a way supersedes Boost Bind + Boost Lambda, you could use Boost Phoenix:
boost::for_each(pntVec, std::cout << bind(&pnt::_type, arg1) << "\n");
or even without bind, if you don't fear a bit of arcane syntax:
boost::for_each(v, std::cout << (arg1->*&pnt::_type) << "\n");
That's pretty expressive. See it Live On Coliru
Also, note that there's mem_fn in Boost/c++11: pntVec | transformed(mem_fn(&pnt::_type))
I have a method like this:
std::map<std::string, int> container;
void myMap(std::initializer_list<std::pair<std::string, int>> input)
{
// insert 'input' into map...
}
I can call that method like this:
myMap({
{"foo", 1}
});
How I can convert my custom argument and insert into the map?
I tried:
container = input;
container(input);
But don't work because the parameter of map is only std::initializer_list and there's no std::pair there.
Thank you all.
container.insert(input.begin(), input.end());
If you want to replace the contents of the map. do container.clear(); first.
Your problem is that the value_type of std::map<std::string,int> is not
std::pair<std::string,int>. It is std::pair<const std::string, int>. Note the const on the key. This works fine:
std::map<std::string, int> container;
void myMap(std::initializer_list<std::pair<const std::string, int>> input) {
container = input;
}
If you can't change your function's signature, you have to write a loop or use std::copy to convert each input element into the value_type of the container. But I'm guessing you probably can, since it's called myMap and not otherGuysMap :) .
I have std::map<int, std::pair<short, float> >, and I need to find the minimal short in this map. How can I use boost::bind with std::min_element() for this?
boost::lambda?
The map iterator will give you a pair where first is the int key and second is the map's pair value, so if you had an iterator it, you'd want the minimum of all the it->second.first values. The min_element function expects a comparison function for its third argument, so you need to build a comparison function that projects second.first of its two arguments.
We'll start with some typedefs to make the code more readable:
typedef std::pair<short, float> val_type;
typedef std::map<int, val_type> map_type;
map_type m;
We're going to use Boost.Lambda for its overloaded operators, allowing us to use operator<. Boost.Bind can bind member variables as well as member functions, so we'll take advantage of that, too.
#include <boost/bind.hpp>
#include <boost/lambda/lambda.hpp>
using boost::bind;
// Comparison is (_1.second.first < _2.second.first)
std::cout <<
std::min_element(m.begin(), m.end(),
bind(&val_type::first, bind(&map_type::iterator::value_type::second, _1))
<
bind(&val_type::first, bind(&map_type::iterator::value_type::second, _2))
)->second.first;
That will also work with boost::lambda::bind.
min_element(map.begin(), map.end(),
compose2(less<short>(),
compose1(select1st<pair<short, float> >(),
select2nd<map<int, pair<short, float>
>::value_type>()),
compose1(select1st<pair<short, float> >(),
select2nd<map<int, pair<short, float>
>::value_type>()))
).second.first;
(Of course, somebody's going to complain that this is an abuse of STL and that these are extensions not in the C++ standard…)
bind cannot do this by itself, because first and second are exposed as fields, not methods (so you can't get away with something like mem_fun).
You could do this using your own functor of course though:
template <typename F, typename S>
struct select_first : std::binary_function<std::pair<F, S>&, F&>
{
F& operator()(std::pair<F, S>& toConvert)
{
return toConvert.first;
}
};
When I work with BOOST_FOREACH, there isn't a problem with simple templates as vector. But when I try to iterate through map > for example I need to typedef the element type.
Is there any workaround?
There is a problem because it is a macro, and therefore cannot handle types containing commas (preprocessor doesn't know about templates).
You can also declare the variable before the loop, see documentation.
std::map<int, double> my_map;
//1)
typedef std::pair<int, double> MyPair;
BOOST_FOREACH(MyPair p, my_map) { ... }
//2)
std::pair<int, double> p;
BOOST_FOREACH(p, my_map) { ... }
Edit:
There is a further complication with std::map in particular: the value_type is not std::pair<Key, Value>, but std::pair<const Key, Value>.
Hence, if you go with the typedef, a more proper way (and the only way if you want to use a reference in the foreach loop) is to use
typedef std::pair<const int, double> MyPair;
//or
typedef std::map<int, double>::value_type MyPair;
BOOST_FOREACH(MyPair& ref, my_map) { ... }
However, that won't work if you want to use a variable declared before the loop, since you can't assign to a std::pair<const int, double> instance later (can't assign to the const field), in which case you can only use pair<int, double> as boost's manual shows.
If you need to iterate over a map, the easiest way is to use tuples, since getting the correct type in order to typedef, is troublesome. Here is how you can use tuples:
std::map<int, double> my_map;
int key;
double value;
BOOST_FOREACH(boost::tie(key, value), my_map) { ... }
Just a note, the commas will work here because parenthesis are placed around key and value. The preprocessor only understands commas and parenthesis(and c99 requires it to understand quotation marks also). So, it can't parse the <> in std::pair<int, double>. However, we can use parenthesis to help the preprocessor. For example, if we have a a function that returns a container that is called like this:
BOOST_FOREACH(int i, foo<int, int>()) { ... } //This won't compile
So, we can place parenthesis around an expression and it will help the preprocessor:
BOOST_FOREACH(int i, (foo<int, int>())) { ... } //This will compile
However, in the case of a map, we can't place parenthesis around the declaration(because its not an expression). So this won't work:
BOOST_FOREACH((std::pair<int, double> p), my_map) { ... } //This won't work
Because it will get transformed into something like this (std::pair<int, double> p) = *it, and that, of course, is incorrect C++. But using a tie will work:
BOOST_FOREACH(tie(key, value), my_map) { ... } //This will work
We just need to declare key and value outside of the loop(as shown above). Plus, it can make the loop have more meaningful names. You can write key instead of p.first, and value instead of p.second.
BOOST_FOREACH_PAIR is another option that works well in our experience:
http://lists.boost.org/Archives/boost/2009/09/156345.php
http://lists.boost.org/Archives/boost/2009/09/156366.php
This can be as simple as this:
BOOST_FOREACH(auto& p, my_map) { ... }
Using the C++11 standard, auto is like var in C#, it will do
BOOST_FOREACH(std::pair<int, double>& p, my_map) { ... }