using BOOST_FOREACH with std::map

34,852

Solution 1

The problem is with the first member of the pair, which should be const. Try this:

typedef std::map<int, int> map_t;
map_t mmap;  
BOOST_FOREACH( map_t::value_type &i, mmap )
    i.second++;

Solution 2

This is an old thread, but there is a more convenient solution.

boost has the notion of 'range adapters' that perform a transformation on iterator ranges. There are specific range adapters for this exact use case (iterating over map keys or values): boost::adaptors::map_values and boost::adaptors::map_keys.

So you could iterate over map values like this:

BOOST_FOREACH(int& size, mmap | boost::adaptors::map_values)
{ 
    ++size;
}

More information here.

Solution 3

Another option is to use BOOST_FOREACH_PAIR, see my answer here:

BOOST_FOREACH & templates without typedef

Share:
34,852

Related videos on Youtube

kmote
Author by

kmote

I graduated from Washington State University in Computer Science (undergrad + masters). I've spent over 10 years in software development for a National Laboratory, a startup engineering company, and a nuclear processing plant. This has provided me with a diverse set of experiences and skills. I have worked extensively in such technologies as C++ (w/ MFC, STL, &amp; Boost), C#, Python, and Qt. I'm also quite familiar with VB.Net, HTML/XML, SQL, Java, and Open Inventor as well as tools like Visual Studio, JIRA, and Subversion. I have a strong background in mathematics &amp; graphics and have delved into graph &amp; network theory, information visualization, data analytics, SCADA/HMIs, and artificial intelligence. I'm a Windows expert with Linux/Mac experience. Also, I'm not quite as old as I look. http://kevinmote.wordpress.com http://www.linkedin.com/in/kevinmote

Updated on October 14, 2020

Comments

  • kmote
    kmote over 3 years

    I'd like to iterate over a std::map using BOOST_FOREACH and edit the values. I can't quite get it.

    typedef std::pair<int, int> IdSizePair_t;
    std::map<int,int> mmap;    
    mmap[1] = 1;
    mmap[2] = 2;
    mmap[3] = 3;
    BOOST_FOREACH( IdSizePair_t i, mmap )
        i.second++;
    // mmap should contain {2,3,4} here
    

    Of course this doesn't change anything because I'm not iterating by reference. So I substitute this line instead (as per the example in the Boost docs):

    BOOST_FOREACH( IdSizePair_t &i, mmap )
    

    and I get the compiler error:

    error C2440: 'initializing' : 
    cannot convert from 'std::pair<_Ty1,_Ty2>' to 'IdSizePair_t &'
        with
        [
            _Ty1=const int,
            _Ty2=int
        ]
    

    Any suggestions?

    • Edison Gustavo Muenz
      Edison Gustavo Muenz about 15 years
      What compiler are you using? I tried your code on VS2008 and it worked correctly. I tested hvint's answer too and it worked. I'm using boost 1.36, if that matters.
    • Johannes Schaub - litb
      Johannes Schaub - litb about 15 years
      you probably forgot the & ? without that, it copies the other pair, and constness won't matter then.
  • kmote
    kmote about 15 years
    Thanks, hvint. That did it. Also (after reading your comment) I realized that another way to fix it is to change the first line of my original code to this: typedef std::pair<const int, int> IdSizePair_ty; (which allows me to iterate by reference)
  • Johannes Schaub - litb
    Johannes Schaub - litb about 15 years
    kmote, yes, actually that is what i proposed in my answer (which i deleted when i saw hvint one's). Also, do you know why it behaves that way? I'll undelete mine if you need some explanation.
  • Jim Morris
    Jim Morris about 13 years
    In answer to stackoverflow.com/questions/795443/… "I get a compile error: error C2065: 'i' : undeclared identifier" I got the same error, until I realized that I had not #include <boost/foreach.hpp> Once I added that the solution worked perfectly. It's odd you don't get an error saying BOOST_FOREACH is undeclared.
  • Rian Sanderson
    Rian Sanderson over 12 years
    I like the look of BOOST_FOREACH_PAIR, but I don't see any official references to it and it's not in the 1.46 version I'm using. Did it ever get included into an official release?
  • Trebor Rude
    Trebor Rude over 8 years
    It's interesting to note that the typedef is necessary, as (at least in g++ 4.8.5) leaving it out will make the preprocessor believe that three arguments have been passed to BOOST_FOREACH instead of just two (due to the comma in the template arguments to std::map).
  • scai
    scai about 8 years
    For this solution <boost/range/adaptor/map.hpp> needs to be included.
  • baderous
    baderous over 7 years
    That was just a homemade macro - it was never implemented into boost. Ended as a wontfix (in favor of C++11 range-based loops) in svn.boost.org/trac/boost/ticket/3469