views:

364

answers:

8

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?

A: 

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
No, it cannot! The iterator gives you always a pair (key,value)
PierreBdR
You are right, it must be a map.begin() and map.end()
vodkhang
+3  A: 

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
algorithms are much more efficient
wheaties
@wheaties: Care to elaborate ?
ereOn
@wheaties: they are written in same C++. In general, _algorithms_ are less efficient because they are _generic_
bobah
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
from GCC standard library: template<typename _InputIterator, typename _Function> _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
Premature generalization is the root of another kind of evil.
KennyTM
@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.
Noah Roberts
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
@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
@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.
Noah Roberts
@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.
Noah Roberts
@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
@Noah Roberts: isn't this the kind of optimization a compiler will do anyway ?
ereOn
@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
@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.
Noah Roberts
@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
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...
GMan
@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.
Noah Roberts
...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 }` and `for (vec_element v }`. 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.
GMan
@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.
Noah Roberts
@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
+2  A: 

You can iterate through a std::map object. Each iterator will point to a std::pair<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<int, MyClass> as an argument instead.

Example:

function CallMyMethod(std::pair<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);
ereOn
Thanks for your answer, but I'd like to avoid creating my own loop.
Antonio Perez
@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
Antonio Perez
@Antonio: The question was edited so that you can use `std::for_each` as well. Give it a try ;)
ereOn
A: 

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
A: 

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
That's suboptimal. Copying **every** instance of `MyClass` and allocating a `std::vector` for this is not exactly optimization...
ereOn
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
I guess we can assume the OP will prefer an optimized solution when it exists... no ?
ereOn
A: 

Instead of trying to do something crazy why not generalize:

template<typename T, typename V, func MemFunc>
class Foo{
    MemFunc _m_MemberFunc;
public:
    Foo(MemFunc _func) : m_MemberFunc( _func ){}
    operator(pair<T,V> _item){
        //stuff
    }
};

std::for_each(map.begin(), map.end(), Foo(mem_fun(&MyClass::Method) );

Or maybe I've messed something up. Sorry, rushing to run to lunch.

wheaties
That's a nice answer but you need a helper function to build Foo, otherwise you have to also pass the template parameters (which you either missed or they've been turned into html and blanked out). By helper function I mean like how bind1st is a helper function that returns a binder_1st<.....>.
Noah Roberts
+1  A: 

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
If you're a VS user and you know how to access STL extensions, please edit this for cross-platform compatibility.
David Joyner
A: 

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