how to iterate through boost unordered_map? - c++

I just want to iterate through the members of an unordered map.
There are many simple examples on the web, including on this site, and yet none of them will compile. Apparently some examples are from a previous non-standard STL version, some are just old, and some are so new that my gcc 4.7.2 can't handle them. Please do not suggest the new auto iterator from C++11. I will get there some day when all my libraries are validated for that. Until then, I just want the old one to work. (see below for what I have tried)
Here is my test code:
#include <iostream>
#include <boost/unordered_map.hpp>
#include <string>
int main(int argc,char *argv[]) {
boost::unordered::unordered_map<std::string,int> umap;
//can't get gcc to accept the value_type()...
//umap.insert(boost::unordered_map::value_type("alpha",1));
//umap.insert(boost::unordered_map::value_type("beta",2));
//umap.insert(boost::unordered_map::value_type("gamma",3));
umap["alpha"]=1; //this works
umap["beta"]=2;
umap["gamma"]=3;
//can't get gcc to compile the iterator
//for (boost::unordered_map::iterator it=umap.begin();it!=umap.end();++it)
// std::cout << it->first <<", " << it->second << std::endl;
//gcc does not like it this way either
//for (int x=0;x<umap.size();x++)
// std::cout << x << " : " << umap[x].first << " = " << umap[x].second << std::endl;
//will gcc take this? No it does not
//for (int x=0;x<umap.size();x++)
// std::cout << x << " : " << umap[x] << std::endl;
//this does not work
//boost::unordered::unordered_map::iterator<std::string,int> it;
//this does not work
//boost::unordered::unordered_map::iterator it;
//for (it=umap.begin();it!=umap.end();++it)
// std::cout << it->first <<", " << it->second << std::endl;
//this does not work
//BOOST_FOREACH(boost::unordered_map::value_type value, umap) {
// std::cout << value.second;
// }
//std::cout << std::endl;
//this does not work either
//BOOST_FOREACH(boost::unordered_map::value_type<std::string,int> value, umap) {
// std::cout << value.second;
// }
//std::cout << std::endl;
std::cout << "umap size: " << umap.size() << std::endl;
std::cout << "umap max size: " << umap.max_size() << std::endl;
std::cout << "find alpha: " << (umap.find("alpha")!=umap.end()) << std::endl;
std::cout << "count beta: " << umap.count("beta") << std::endl;
}
Most of the errors are a variation of this:
error: 'template<class K, class T, class H, class P, class A> class boost::unordered::unordered_map' used without template parameters
Here is my build command:
g++ -I..\boost umap.cpp
I should be embarrassed for getting stuck on such a beginner's question, but from the volume of similar questions I am finding, this is just hard enough to stop a lot of people in their tracks. I have written hash containers before (back when it was recommended NOT to use STL) and I am very tempted to just write my own... but the right thing to do is learn to use as many existing tools as possible... help!
I've looked at the following questions on stackoverflow where I haven't found an answer:
iterate through unordered_map using boost_foreach
I tried:
BOOST_FOREACH(boost::unordered_map::value_type& value, umap) {
but it gives the same error I show below.
Unordered_map iterator invalidation
This one is close, but not quite my issue:
Iterator invalidation in boost::unordered_map
This one uses auto
and I can't switch compilers at this time.
C++ some questions on boost::unordered_map & boost::hash
This one is mostly about the theory of maps:
how to use boost::unordered_map
This is a rather complicated example, but you will see in my code I am already trying to declare iterators... they just won't compile.
How to use BOOST_FOREACH with an Unordered_map?
This is a nice example, but
it just does not compile. I tried a version of this in my code.
IT WORKS !
Here is the working code:
#include <iostream>
#include <boost/unordered_map.hpp>
#include <string>
int main(int argc,char *argv[]) {
boost::unordered::unordered_map<std::string,int> umap;
umap["alpha"]=1;
umap["beta"]=2;
umap["gamma"]=3;
boost::unordered::unordered_map<std::string,int>::iterator it;
for (it=umap.begin();it!=umap.end();++it)
std::cout << it->first <<", " << it->second << std::endl;
std::cout << "umap size: " << umap.size() << std::endl;
std::cout << "umap max size: " << umap.max_size() << std::endl;
std::cout << "find alpha: " << (umap.find("alpha")!=umap.end()) << std::endl;
std::cout << "count beta: " << umap.count("beta") << std::endl;
}
It was a syntax error. I was putting the type in the wrong place when declaring the iterator.
Thanks everyone for your responses.

try changing boost::unordered::unordered_map::iterator it; it to boost::unordered::unordered_map<std::string,int>::iterator it;
NOTE:
It is also possible, and a good idea in more complex situations, to create a typedef of it, such as typedef boost::unordered::unordered_map<std::string,int>::iterator UMapStringIntIt;, or whatever you may call it.

The answer is in the question, but the simple solution is here for your convenience:
#include <iostream>
#include <boost/unordered_map.hpp>
#include <string>
int main(int argc,char *argv[])
{
boost::unordered::unordered_map<std::string,int> umap;
umap["alpha"]=1;
umap["beta"]=2;
umap["gamma"]=3;
for ( auto it= umap.begin(); it != umap.end(); ++it )
std::cout << it->first <<", " << it->second << std::endl;
}

Related

Effectively getting items from map based on specific sort

I have a fairly easy problem: I have an std::map<int,T> and another std::set<int> (can be std::vector or similar too).
In the map I store items, and in the other container I'm storing favorites (of the map).
At some point, I'd need to retrieve (all) items from the map, but starting with the favorites defined by the other container.
Here is my minimal repro, I solved it very ugly, and ineffective:
#include <iostream>
#include <string>
#include <set>
#include <map>
using namespace std;
map<int, string> myMap;
set<int> myFavorites;
int main()
{
myMap.emplace(1, "but I don't like this");
myMap.emplace(12, "So it will go below");
myMap.emplace(31, "This one will come first, and");
myMap.emplace(44, "under my favorites");
myMap.emplace(52, "then this will follow");
myFavorites.insert(52);
myFavorites.insert(31);
cout << "My map:" << endl;
for(auto p : myMap) {
cout << "#" << p.first << "=" << p.second << endl;
}
cout << endl << "My favorites:" << endl;
for(auto p : myFavorites) {
cout << "#" << p << endl;
}
cout << endl << "All items starting with my favorites:" << endl;
for(auto p : myFavorites) {
auto item = myMap.find(p);
if (item != myMap.end()) cout << "#" << item->first << "=" << item->second << endl;
}
for(auto p : myMap) {
if (myFavorites.find(p.first) != myFavorites.end()) continue;
cout << "#" << p.first << "=" << p.second << endl;
}
}
What really bothers me is the last loop, where each iterations would call find on the set.
Required output is:
All items starting with my favorites:
#31=This one will come first, and
#52=then this will follow
#1=but I don't like this
#12=So it will go below
#44=under my favorites
Here is the above source in Coliru for making it easier: https://coliru.stacked-crooked.com/a/731fa76d90bfab00
Both map and set might be changed, but replacements needs to implement the same interfaces as originals.
I'm looking for a way to solve this more efficient than my original "brute-force" one.
Please note: map must not be "reordered"! I just need to query (retrieve) its items with custom sorting!
Note2: I know map can have a comparison operator. But I'd need to have the original order usually, and sometimes I'd need to have the custom sort!
Note3: Boost is not available and compiler is C++14 capable.
Both std::map and std::set use the same strict weak ordering for ordering its contents.
You can take advantage of this. You know that if you iterate over the map you will get the keys in the same order as they are in the set, therefore all it takes is a little bit of clever logic, something like:
auto map_iter=myMap.begin();
for(auto p : myFavorites) {
while (map_iter != myMap.end())
{
if (map_iter->first == p)
cout << "#" << map_iter->first << "=" << map_iter->second << endl;
if (map_iter->first > p)
break;
++map_iter;
}
}
It may still make sense to use find() in some edge cases, specifically when myFavorites is significantly smaller than myMap, in which case a few calls to find() might be faster than iterating over (most of) the entire map.

Reading out Pixel Values, png++, C++

I am trying to load the pixel rgb/ga information of a png image into a matrix, using the library png++, to do some computations with them.
My Code (which does not work at the moment):
#include <iostream>
#include <png++/image.hpp>
#include <png++/rgb_pixel.hpp>
int main(int argc, const char * argv[]) {
const std::string path="img_03.png";
png::image< png::basic_rgb_pixel <unsigned char> > pic(path);
pixel=pic.get_pixel(0, 0);
pixelp = &pixel;
std::cout << "value=" << pic[10][10].red << std::endl; //output: '?'
std::cout << "value=" << pixel.red << std::endl; //nothing
std::cout << "pointer=" << pixelp << std::endl; //delivers adress
pic.read(path);
std::cout << "value=" << pic[10][10].red << std::endl; //nothing
pic.write("picOutput.png"); //same picture
return 0;
}
However, none of those methods work to get the rgb values of each pixel.
If there is another way to get rgb/ga information of each pixel, please mention it.
The line pic.write("picOutput.png"); delivers the same png i loaded in the line pic.read(path). This is a personal exercise for me to get more used to C++, criticise my code as much as you can.
Thanks!
Here comes the solution:
change line:
std::cout << "value=" << pic[10][10].red << std::endl; //nothing
with:
std::cout << "value=" << (int) pic[10][10].red << std::endl; //nothing
because std::cout can't output types of unsigned char.
Thanks to Alex!
For in-depth explanation, look here:
cout not printing unsigned char

Using a boost::fusion::map in boost::spirit::karma

I am using boost spirit to parse some text files into a data structure and now I am beginning to generate text from this data structure (using spirit karma).
One attempt at a data structure is a boost::fusion::map (as suggested in an answer to
this question). But although I can use boost::spirit::qi::parse() and get data in it easily, when I tried to generate text from it using karma, I failed.
Below is my attempt (look especially at the "map_data" type). After some reading and playing around with other fusion types, I found boost::fusion::vector and BOOST_FUSION_DEFINE_ASSOC_STRUCT. I succeeded to generate output with both of them, but they don't seem ideal: in vector you cannot access a member using a name (it is like a tuple) -- and in the other solution, I don't think I need both ways (member name and key type) to access the members.
#include <iostream>
#include <string>
#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/include/map.hpp>
#include <boost/fusion/include/make_map.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/include/transform.hpp>
struct sb_key;
struct id_key;
using boost::fusion::pair;
typedef boost::fusion::map
< pair<sb_key, int>
, pair<id_key, unsigned long>
> map_data;
typedef boost::fusion::vector < int, unsigned long > vector_data;
#include <boost/fusion/include/define_assoc_struct.hpp>
BOOST_FUSION_DEFINE_ASSOC_STRUCT(
(), assocstruct_data,
(int, a, sb_key)
(unsigned long, b, id_key))
namespace karma = boost::spirit::karma;
template <typename X>
std::string to_string ( const X& data )
{
std::string generated;
std::back_insert_iterator<std::string> sink(generated);
karma::generate_delimited ( sink, karma::int_ << karma::ulong_, karma::space, data );
return generated;
}
int main()
{
map_data d1(boost::fusion::make_map<sb_key, id_key>(234, 35314988526ul));
vector_data d2(boost::fusion::make_vector(234, 35314988526ul));
assocstruct_data d3(234,35314988526ul);
std::cout << "map_data as_vector: " << boost::fusion::as_vector(d1) << std::endl;
//std::cout << "map_data to_string: " << to_string(d1) << std::endl; //*FAIL No 1*
std::cout << "at_key (sb_key): " << boost::fusion::at_key<sb_key>(d1) << boost::fusion::at_c<0>(d1) << std::endl << std::endl;
std::cout << "vector_data: " << d2 << std::endl;
std::cout << "vector_data to_string: " << to_string(d2) << std::endl << std::endl;
std::cout << "assoc_struct as_vector: " << boost::fusion::as_vector(d3) << std::endl;
std::cout << "assoc_struct to_string: " << to_string(d3) << std::endl;
std::cout << "at_key (sb_key): " << boost::fusion::at_key<sb_key>(d3) << d3.a << boost::fusion::at_c<0>(d3) << std::endl;
return 0;
}
Including the commented line gives lots of pages of compilation errors, among which notably something like:
no known conversion for argument 1 from ‘boost::fusion::pair’ to ‘double’
no known conversion for argument 1 from ‘boost::fusion::pair’ to ‘float’
Might it be that to_string needs the values of the map_data, and not the pairs? Though I am not good with templates, I tried to get a vector from a map using transform in the following way
template <typename P>
struct take_second
{
typename P::second_type operator() (P p)
{
return p.second;
}
};
// ... inside main()
pair <char, int> ff(32);
std::cout << "take_second (expect 32): "
<< take_second<pair<char,int>>()(ff) << std::endl;
std::cout << "transform map_data and to_string: "
<< to_string(boost::fusion::transform(d1, take_second<>())); //*FAIL No 2*
But I don't know what types am I supposed to give when instantiating take_second and anyway I think there must be an easier way to get (iterate over) the values of a map (is there?)
If you answer this question, please also give your opinion on whether using an ASSOC_STRUCT or a map is better.
I think I noticed your question on the [spirit-general] list earlier.
It got 14 views there - and I did some fairly deep investigation. Sadly, to the best of my knowledge I don't think Spirit has any support for associate Fusion structures.
In fact, outside MSM and Phoenix, there was no place in boost where I see fusion::map being used.
Is there a chance you could just use std::map/std::pair instead? Here's a tiny proof of concept:
#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/adapted.hpp>
int main()
{
const auto data = std::map<std::string, double> {
{ "pi", 3.1415925 },
{ "e", 2.718281828 },
{ "Answer", 42 } };
namespace karma = boost::spirit::karma;
std::cout << karma::format((karma::string << " = " << karma::double_) % karma::eol, data)
<< std::endl;
}
Output:
Answer = 42.0
e = 2.718
pi = 3.142

C++ STL map with custom comparator storing null pointers

I'm trying to write a copy constructor for an object managing a STL map containing pointers, where the key is a string. However, when I attempt to insert new values in the map, the pointers are set to NULL:
// ...
for(std::map<std::string, data_base*, order>::const_iterator it = other.elements.begin();
it != other.elements.end(); ++it){
data_base *t = it->second->clone();
std::cout << "CLONE: " << std::hex << t << std::endl;
elements[it->first] = t;
std::cout << "INSERTED: " << std::hex << elements[it->first] << std::endl;
}
// ...
other is the object being copied and elements the map. The clone() method returns a pointer to a new object (via new).
Running the code above I get something like:
CLONE: 0xcfbbc0
INSERTED: 0
I'm not a very experienced programmer and this issue is probably simple to fix, but I didnt find any solution to it searching around.
Thanks a lot for your time.
I don't see any problem with this code, other than maybe
std::map<std::string, data_base*, order>::const_iterator it
Here order gives the key comparator to use to sort the pairs contained in the map (often implemented as a tree).
Maybe you're doing something wrong in it, making your [] operator don't find the right ke, making your last line logging a new pair with a null ptr.
First, try without that order, using the default key-comparator (std::less), then if it don't work, post your order definition and the map declaration. If it's not enough, just provide a simple complete program that reproduce the problem.
I just wrote a simple similar test, using the default key-comparator :
#include <map>
#include <string>
#include <iostream>
struct Data
{
int k;
Data* clone() { return new Data(); }
};
typedef std::map< std::string, Data* > DataMap;
DataMap data_map;
int main()
{
data_map[ "hello" ] = new Data();
data_map[ "world" ] = new Data();
DataMap other_map;
for( DataMap::const_iterator it = data_map.begin(); it != data_map.end(); ++it)
{
Data*t = it->second->clone();
std::cout << "CLONE: " << std::hex << t << std::endl;
other_map[it->first] = t;
std::cout << "INSERTED: " << std::hex << other_map[it->first] << std::endl;
}
std::cin.ignore();
return 0;
}
On VS2010SP1, this outputs :
CLONE: 00034DD0
INSERTED: 00034DD0
CLONE: 00035098
INSERTED: 00035098
So it should be the problem, or maybe you're doing something wrong before.
Try this out, to help debug the issue. I'd recommend double-checking that the order function is correct. You can remove it to use std::less<T>, which is known to work.
// ...
typedef std::map<std::string, data_base*, order> string_db_map;
for(string_db_map::const_iterator it = other.elements.begin();
it != other.elements.end();
++it)
{
data_base *t = it->second->clone();
std::cout << "CLONE: " << std::hex << t << std::endl;
std::pair<string_db_map::iterator, bool) result = elements.insert(
string_db_map::value_type( it->first, t));
if ( !result.second )
{
std::cout << "element['" << it->first << "'] was already present, and replaced." << std::endl;
}
std::coud << "INSERTED [iterator]: " << std::hex << (*result.first).second << std::endl;
std::cout << "INSERTED [indexed]: " << std::hex << elements[it->first] << std::endl;
}
// ...

How to enumerate a BOOST_ENUM with BOOST_FOREACH?

Can somebody please explain me how to enumerate a BOOST_ENUM using BOOST_FOREACH ?
The example below show that I got it to work with std::for_each, but not with BOOST_FOREACH.
Sample code :
BOOST_ENUM_VALUES( MyEnum,
const char *,
(xMin)("xMin")
(xMax)("xMax")
(yMin)("yMin")
(yMax)("yMax")
);
void blah(const MyEnum & val) // working demo with std_foreach
{
std::cout << "index=" << val.index() << " val=" << val.value() << " str=" << val.str() << std::endl;
}
void foo()
{
//BOOST_FOREACH : does not compile...
BOOST_FOREACH(MyEnum myEnum, MyEnum() ) // I tried to construct a "dummy" enum in order to use its iterator with no luck...
{
std::cout << "index=" << myEnum.index() << " val=" << myEnum.value() << " str=" << myEnum.str() << std::endl;
}
//std::for_each : works...
std::for_each(MyEnum::begin(), MyEnum::end(), blah);
}
Many thanks in advance!
Edit: as mentioned in the answer, the code does work with the newest codebase of boost.
Your example code above compiles and runs just fine for me with gcc 4.5.1 and vc2010 (after adding the corresponding #include's, that is). I tried with enum_rev4.6 from the vault. What compilation errors do you see?