Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a member function to for_each in C++03 (no boost, no c++11)

Tags:

c++

stl

c++03

The "solution" below compiles but it is not what I want. I would like to pass the put member function to for_each and not *this. Using boost is NOT an option. Can this be solved within C++03?

#include <algorithm>
#include <functional>
#include <vector>
using namespace std;

class Wheel { };

class Car {

public:

    void process(const vector<Wheel>& wheel) {

        for_each(wheel.begin(), wheel.end(), *this);
    }

    void operator()(const Wheel& w) { put(w); }

private:

    void put(const Wheel& w) { }
};

int main() {

    vector<Wheel> w(4);

    Car c;

    c.process(w);

    return 0;
}
like image 725
Ali Avatar asked Jan 09 '11 23:01

Ali


3 Answers

Yes it can, using a combination of the mem_fun and bind1st templates:

void process(const vector<Wheel>& wheel) {
    for_each(wheel.begin(), wheel.end(), bind1st(mem_fun(&Car::put), this));
}

The call to mem_fun creates a new function object that takes in two arguments - a Car* to act as the receiver and a Wheel, then calls put with the first parameter as the receiver and the second parameter as the argument. Calling bind1st then locks the receiver object as first parameter of this function in place.

However, I think you will need to make one small change to this code to get it to work. The bind1st adapter doesn't play well with functions that take their arguments by const reference, so you might need to change put so that it takes a Wheel by value rather than by reference.

like image 153
templatetypedef Avatar answered Nov 15 '22 03:11

templatetypedef


You can use mem_fun_ref: see here.

mem_fun_ref should work in your case where you have vector of objects:

for_each(wheel.begin(), wheel.end(), mem_fun_ref(&Wheel::put));

Note that the above example changes put to be a member of Wheel and not Car. It should give you an idea of how to use it though.

Use mem_fun if you have a vector of pointers to an object

like image 27
sashang Avatar answered Nov 15 '22 03:11

sashang


Sure- you can just write your own equivalent of boost::mem_func. TR1 has one too. It's a little repetitive if you want increasing numbers of arguments, but not conceptually hard.

template<typename T, typename mem_func_type> struct mem_func_internal;
template<typename T, typename Ret> struct mem_func_internal<T, Ret (T::*)()> {
    typedef Ret(T::* functype)();
    T* obj;
    functype func;
    Ret operator()() {
        return obj->*func();
    }
};
template<typename T, typename Ret, typename ArgType1> struct mem_func_internal<T, Ret (T::*)(ArgType1) {
    typedef Ret(T::* functype)();
    T* obj;
    functype func;
    Ret operator()(ArgType1 arg) {
        return obj->*func(arg);
    }
 }
template<typename T, typename mem_func_type> struct mem_func : public mem_func_internal<T, mem_func_type> {
    mem_func(T* object, mem_func_type mem_func)
        : obj(object)
        , func(mem_func) {}
};
template<typename T, typename mem_func_type> mem_func<T, mem_func_type> bind_mem_func(T* object, mem_func_type func) {
    return mem_func<T, mem_func_type>(object, func);
}
// Usage
std::for_each(wheel.begin(), wheel.end(), bind_mem_func(this, &Car::put));

It's been a while since I wrote code like this, so it might be a little off. But that's the gist of it. So hard to write a usage example without just using a lambda.

like image 44
Puppy Avatar answered Nov 15 '22 03:11

Puppy