63

I have a map where I'd like to perform a call on every data type object member function. I yet know how to do this on any sequence but, is it possible to do it on an associative container?

The closest answer I could find was this: Boost.Bind to access std::map elements in std::for_each. But I cannot use boost in my project so, is there an STL alternative that I'm missing to boost::bind?

If not possible, I thought on creating a temporary sequence for pointers to the data objects and then, call for_each on it, something like this:

class MyClass
{
public:
 void Method() const;
}

std::map<int, MyClass> Map;
//...

std::vector<MyClass*> Vector;
std::transform(Map.begin(), Map.end(), std::back_inserter(Vector), std::mem_fun_ref(&std::map<int, MyClass>::value_type::second));
std::for_each(Vector.begin(), Vector.end(), std::mem_fun(&MyClass::Method));

It looks too obfuscated and I don't really like it. Any suggestions?

Community
  • 1
  • 1
Antonio Pérez
  • 6,702
  • 4
  • 36
  • 61

11 Answers11

152

C++11 allows you to do:

for (const auto& kv : myMap) {
    std::cout << kv.first << " has value " << kv.second << std::endl;
}

C++17 allows you to do:

for (const auto& [key, value] : myMap) {
    std::cout << key << " has value " << value << std::endl;
}

using structured binding.

UPDATE:

const auto is safer if you don't want to modify the map.

Zitrax
  • 19,036
  • 20
  • 88
  • 110
Sebastian
  • 2,876
  • 2
  • 24
  • 28
67

You can iterate through a std::map object. Each iterator will point to a std::pair<const T,S> where T and S are the same types you specified on your map.

Here this would be:

for (std::map<int, MyClass>::iterator it = Map.begin(); it != Map.end(); ++it)
{
  it->second.Method();
}

If you still want to use std::for_each, pass a function that takes a std::pair<const int, MyClass>& as an argument instead.

Example:

void CallMyMethod(std::pair<const int, MyClass>& pair) // could be a class static method as well
{
  pair.second.Method();
}

And pass it to std::for_each:

std::for_each(Map.begin(), Map.end(), CallMyMethod);
Antonio Pérez
  • 6,702
  • 4
  • 36
  • 61
ereOn
  • 53,676
  • 39
  • 161
  • 238
  • 2
    Thanks for your answer, but I'd like to avoid creating my own loop. – Antonio Pérez May 17 '10 at 15:32
  • 2
    @Antonio: Any particular reason for this ? Any template based solution should produce a code which will be **at most** as efficient, or worse. But unlikely faster. I edited my answer to add a shorter (but equivalent solution). – ereOn May 17 '10 at 15:36
  • I just find the use of for_each for this purpose on STL sequences to be cleaner than a for loop (for_each(v.begin(), v.end(), &mem_fun_ref(&MyClass::Method)). So I wandered how to do it on a map. – Antonio Pérez May 17 '10 at 15:46
  • 1
    @Antonio: The question was edited so that you can use `std::for_each` as well. Give it a try ;) – ereOn May 17 '10 at 15:49
  • This doesn't compile because of a small error. When dereferenced, the std::map iterator returns `std::pair`, not `std::pair`. So you need `CallMyMethod` to take `std::pair&` as its argument. – MtnViewJohn Oct 11 '11 at 04:50
  • @ereOn One reason for not wanting a for loop would be so that a whole map could be checked in an assertion – danio Oct 29 '15 at 14:00
17

C++14 brings generic lambdas. Meaning we can use std::for_each very easily:

std::map<int, int> myMap{{1, 2}, {3, 4}, {5, 6}, {7, 8}};

std::for_each(myMap.begin(), myMap.end(), [](const auto &myMapPair) {
    std::cout << "first " << myMapPair.first << " second "
              << myMapPair.second << std::endl;
});

I think std::for_each is sometimes better suited than a simple range based for loop. For example when you only want to loop through a subset of a map.

Christian Rapp
  • 1,853
  • 24
  • 37
8

How about a plain C++? (example fixed according to the note by @Noah Roberts)

for(std::map<int, MyClass>::iterator itr = Map.begin(), itr_end = Map.end(); itr != itr_end; ++itr) {
  itr->second.Method();
}
bobah
  • 18,364
  • 2
  • 37
  • 70
  • algorithms are much more efficient – wheaties May 17 '10 at 15:33
  • @wheaties: Care to elaborate ? – ereOn May 17 '10 at 15:35
  • @wheaties: they are written in same C++. In general, _algorithms_ are less efficient because they are _generic_ – bobah May 17 '10 at 15:38
  • Scott Myers, Effective C++. Prefer algorithms over hand loops. In general, the library creators can create optimizations within the code based on the implementation of the containers that no mere mortal may know. – wheaties May 17 '10 at 15:40
  • from GCC standard library: template _Function for_each(_InputIterator __first, _InputIterator __last, _Function __f) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) __glibcxx_requires_valid_range(__first, __last); for (; __first != __last; ++__first) __f(*__first); return __f; } – bobah May 17 '10 at 15:47
  • 10
    Premature generalization is the root of another kind of evil. – kennytm May 17 '10 at 15:56
  • @bobah - note that the implementation you posted in this comment is already more efficient than the implementation you posted in your answer. Can you see why? That said, for_each is not a likely algorithm to have any optimizations. The requirements for it are very specific and it's not allowed to vary. Other algorithms can be tag dispatched and such to reach an Iterator specific implementation that works better. This having already been done there's no reason to attempt rewriting them. This is just one reason why they're better. – Edward Strange May 17 '10 at 15:58
  • 3
    Arguably, they are harder for the next programmer to understand and maintainable code is worth more than optimized code unless you have identified a bottleneck using a profiling tool. – jmucchiello May 17 '10 at 16:06
  • @Noah Roberts: I agree. But can you explain why the implementation posted by @bobah on his last comment is better than his answer ? I can't really see why and the poor formatting doesn't help. – ereOn May 17 '10 at 16:17
  • @ereOn - because he calls .end() in each iteration of his for loop while the algorithm accepts it as a parameter and keeps it. Of course, this is bad if you actually NEED to call .end() each time but this is generally not the case. – Edward Strange May 17 '10 at 16:20
  • 1
    @jmucchiello - that's up to taste of course but I would beg to differ with you. Quite the opposite in fact since the algorithms are named after what the loop is supposed to be doing instead of having to decipher that by the steps occurring in the loop. – Edward Strange May 17 '10 at 16:21
  • @Noah Roberts: good note, I'll fix an example. regarding the rest -- to read my example you don't even have to be a C++ developer, while to read for_each(beg, end, op) the average developer should ask google – bobah May 17 '10 at 16:25
  • @Noah Roberts: isn't this the kind of optimization a compiler will do anyway ? – ereOn May 17 '10 at 16:37
  • @ereOn: It depends on how complex your loop is, and whether or not it can verify that nothing it does will effect the value returned by `end()`, and whether or not it can verify that `end()` doesn't have any side effects that would preclude it from being pulled outside the loop. – Dennis Zickefoose May 17 '10 at 16:44
  • @ereOn - I don't think that it can. There are too many ways in which the result of .end() could be changed. There are of course many optimizations the compiler could do, and the difference is generally going to be too small to worry about...but this whole thread is about micro-optimizations anyway. – Edward Strange May 17 '10 at 16:46
  • @Noah, I'm actually referring to the transform step here. Assuming Method knows nothing about the vector it makes more sense to me to loop over the map, push_back to the vector and call the method right there. Looping over the data to create a vector and then looping over the vector to call a bunch of functions seems like more work. Admittedly, I may be paying too much attention to the example. But in my experience, tight loops (where you just call a single method on one object in a collection of those objects) don't come up that often and thus for_each is not a commonly needed tool. – jmucchiello May 17 '10 at 16:48
  • Alright. @wheaties: I wouldn't say they are *much* more efficient, but rather that they can and often are more optimized. (Like `std::copy` resorting to `memmove` if the type is POD.) @bobah: Generic implies slower? I'd love to hear the reasoning or see evidence for that. A template function will just instantiate a new function when used, and then probably get inlined by the compiler. I fail to see how that could make it any slower. And like wheaties said, it can sometimes even generate faster code. And like @Noah shows, there are already some key differences. (Though those may be and... – GManNickG May 17 '10 at 16:48
  • @bobah - well then your version of "average developer" must be a drooling brain stem. I'll admit that when I was bright green I had some trouble understanding the concept of concepts, especially stuff like Predicate or Strict-Weak-Ordering. The for_each algorithm though didn't even make me blink and I've never met an "average developer" that had any trouble at all with it. More difficult is all the binders and crap that were in C++03 and earlier. Boost and/or the new additions completely change all that so that algorithms are now readily accessible even to total newbs. – Edward Strange May 17 '10 at 16:50
  • 4
    ...probably are negligible.) That said, I don't like `for_each`. It's clumsy most of the time and isn't terribly expressive. Ideally, I prefer the new range-based for-loop in C++0x: `for (const map_pair& p : the_map) { the_vec.push_back(p.second); }` and `for (vec_element v& : the_vec) { v.method(); }`. Far simpler to read and quite concise. Next would be faking such functionality, such as with Boost's for each macro. If not that, lambda's can help a bit by localizing algorithms, but I think `for_each` is sort of a last resort thing. – GManNickG May 17 '10 at 16:51
  • @jmucchiello - yeah, without boost::bind and various other very important tools the OP is probably better off with loops. The levels of binder and such required to use std::for_each without boost would make the whole thing illegible. Algorithms become a very strong tool with those additions though and especially with lambda functionality in 0x. – Edward Strange May 17 '10 at 16:54
  • @Noah - Exactly. Algorithms without lambdas never made any sense. And the contortions Boost bind goes through to force it to work are painful to deal with if you get errors trying to use them. I think GMan is on the right track though and C++0x's ranged for is infinitely better than std::for_each. – jmucchiello May 17 '10 at 17:35
3

It's unfortunate that you don't have Boost however if your STL implementation has the extensions then you can compose mem_fun_ref and select2nd to create a single functor suitable for use with for_each. The code would look something like this:

#include <algorithm>
#include <map>
#include <ext/functional>   // GNU-specific extension for functor classes missing from standard STL

using namespace __gnu_cxx;  // for compose1 and select2nd

class MyClass
{
public:
    void Method() const;
};

std::map<int, MyClass> Map;

int main(void)
{
    std::for_each(Map.begin(), Map.end(), compose1(std::mem_fun_ref(&MyClass::Method), select2nd<std::map<int, MyClass>::value_type>()));
}

Note that if you don't have access to compose1 (or the unary_compose template) and select2nd, they are fairly easy to write.

David Joyner
  • 22,449
  • 4
  • 28
  • 33
  • If you're a VS user and you know how to access STL extensions, please edit this for cross-platform compatibility. – David Joyner May 17 '10 at 16:04
  • _"Because libstdc++ based its implementation of the STL subsections of the library on the SGI 3.3 implementation, we [GNU] inherited their extensions as well."_ There is a description of what they do, someone may be able to port them. https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.2/group__SGIextensions.html – Orwellophile Jan 19 '17 at 08:39
  • Note, someone has attempted it (untested) here, although it's not well formatted or tested, it did almost compile for me. Seemed to mess up std::pair in the class with a strange error. YMMV. http://computer-programming-forum.com/84-vc-stl/4d17c0a678f187f0.htm – Orwellophile Jan 19 '17 at 08:55
2

For fellow programmers who stumble upon this question from google, there is a good way using boost.

Explained here : Is it possible to use boost::foreach with std::map?

Real example for your convenience :

// typedef in include, given here for info : 
typedef std::map<std::string, std::string> Wt::WEnvironment::CookieMap

Wt::WEnvironment::CookieMap cookie_map = environment.cookies();

BOOST_FOREACH( const Wt::WEnvironment::CookieMap::value_type &cookie, cookie_map )
{
    std::cout << "cookie : " << cookie.first << " = " << cookie.second << endl;
}

enjoy.

Community
  • 1
  • 1
Offirmo
  • 18,962
  • 12
  • 76
  • 97
0

From what I remembered, C++ map can return you an iterator of keys using map.begin(), you can use that iterator to loop over all the keys until it reach map.end(), and get the corresponding value: C++ map

vodkhang
  • 18,639
  • 11
  • 76
  • 110
0

Will it work for you ?

class MyClass;
typedef std::pair<int,MyClass> MyPair;
class MyClass
{
  private:
  void foo() const{};
public:
static void Method(MyPair const& p) 
{
    //......
        p.second.foo();
};
}; 
// ...
std::map<int, MyClass> Map;
//.....
std::for_each(Map.begin(), Map.end(), (&MyClass::Method));
a1ex07
  • 36,826
  • 12
  • 90
  • 103
0

Just an example:

template <class key, class value>
class insertIntoVec
{
public:
    insertIntoVec(std::vector<value>& vec_in):m_vec(vec_in)
    {}

    void operator () (const std::pair<key, value>& rhs)  
    {   
        m_vec.push_back(rhs.second);
    }

private:
    std::vector<value>& m_vec;
};

int main()
{
std::map<int, std::string> aMap;
aMap[1] = "test1";
aMap[2] = "test2";
aMap[3] = "test3";
aMap[4] = "test4";

std::vector<std::string> aVec;

aVec.reserve(aMap.size());
std::for_each(aMap.begin(), aMap.end(),
          insertIntoVec<int, std::string>(aVec) 
    );

}

aJ.
  • 34,624
  • 22
  • 86
  • 128
  • That's suboptimal. Copying **every** instance of `MyClass` and allocating a `std::vector` for this is not exactly optimization... – ereOn May 17 '10 at 15:38
  • The above example is to show how std::for_each can be used to iterate map. There is no question of optimization coming into picture – aJ. May 17 '10 at 15:42
  • I guess we can assume the OP will prefer an optimized solution when it exists... no ? – ereOn May 17 '10 at 15:47
0

I wrote this awhile back to do just what you're looking for.

namespace STLHelpers
{
    //
    // iterator helper type for iterating through the *values* of key/value collections
    //

    /////////////////////////////////////////////
    template<typename _traits>
    struct _value_iterator
    {
        explicit _value_iterator(typename _traits::iterator_type _it)
            : it(_it)
        {
        }

        _value_iterator(const _value_iterator &_other)
            : it(_other.it)
        {
        }

        friend bool operator==(const _value_iterator &lhs, const _value_iterator &rhs)
        {
            return lhs.it == rhs.it;
        }

        friend bool operator!=(const _value_iterator &lhs, const _value_iterator &rhs)
        {
            return !(lhs == rhs);
        }

        _value_iterator &operator++()
        {
            ++it;
            return *this;
        }

        _value_iterator operator++(int)
        {
            _value_iterator t(*this);
            ++*this;
            return t;
        }

        typename _traits::value_type &operator->()
        {
            return **this;
        }

        typename _traits::value_type &operator*()
        {
            return it->second;
        }

        typename _traits::iterator_type it;
    };

    template<typename _tyMap>
    struct _map_iterator_traits
    {
        typedef typename _tyMap::iterator iterator_type;
        typedef typename _tyMap::mapped_type value_type;
    };

    template<typename _tyMap>
    struct _const_map_iterator_traits
    {
        typedef typename _tyMap::const_iterator iterator_type;
        typedef const typename _tyMap::mapped_type value_type;
    };
}
moswald
  • 11,491
  • 7
  • 52
  • 78
0

Here is an example of how you can use for_each for a map.

std::map<int, int> map;

map.insert(std::pair<int, int>(1, 2));
map.insert(std::pair<int, int>(2, 4));
map.insert(std::pair<int, int>(3, 6));

auto f = [](std::pair<int,int> it) {std::cout << it.first + it.second << std::endl; };
std::for_each(map.begin(), map.end(), f);
HmdRmz
  • 1
  • 2