[c++] Use of for_each on map elements

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?

This question is related to c++ algorithm stl stdmap std-pair

The answer is


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


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;
    };
}

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);

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();
}

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) 
    );

}


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.


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.


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.


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.


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));

Examples related to c++

Method Call Chaining; returning a pointer vs a reference? How can I tell if an algorithm is efficient? Difference between opening a file in binary vs text How can compare-and-swap be used for a wait-free mutual exclusion for any shared data structure? Install Qt on Ubuntu #include errors detected in vscode Cannot open include file: 'stdio.h' - Visual Studio Community 2017 - C++ Error How to fix the error "Windows SDK version 8.1" was not found? Visual Studio 2017 errors on standard headers How do I check if a Key is pressed on C++

Examples related to algorithm

How can I tell if an algorithm is efficient? Find the smallest positive integer that does not occur in a given sequence Efficiently getting all divisors of a given number Peak signal detection in realtime timeseries data What is the optimal algorithm for the game 2048? How can I sort a std::map first by value, then by key? Finding square root without using sqrt function? Fastest way to flatten / un-flatten nested JSON objects Mergesort with Python Find common substring between two strings

Examples related to stl

Why is it OK to return a 'vector' from a function? How to remove all the occurrences of a char in c++ string How to use the priority queue STL for objects? use std::fill to populate vector with increasing numbers What does iterator->second mean? How to set initial size of std::vector? Sorting a vector in descending order How do I reverse a C++ vector? Recommended way to insert elements into map Replace an element into a specific position of a vector

Examples related to stdmap

How can I get a value from a map? Recommended way to insert elements into map How can I create my own comparator for a map? How to update std::map after using the find method? What is the preferred/idiomatic way to insert into a map? Use of for_each on map elements How can I use std::maps with user-defined types as key? How to iterate over a std::map full of strings in C++ In STL maps, is it better to use map::insert than []? Initializing a static std::map<int, int> in C++

Examples related to std-pair

How can I print out C++ map values? Adding to a vector of pair What is the preferred/idiomatic way to insert into a map? Use of for_each on map elements What is C# analog of C++ std::pair? What is the equivalent of the C++ Pair<L,R> in Java?