Передача функции-члена for_each в C ++ 03 (без повышения, без c ++ 11) - PullRequest
5 голосов
/ 10 января 2011

«Решение» ниже компилируется, но это не то, что я хочу. Я хотел бы передать функцию-член put в for_each, а не *this. Использование надстройки НЕ вариант. Можно ли это решить в 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;
}

Ответы [ 3 ]

12 голосов
/ 10 января 2011

Да, может, используя комбинацию шаблонов mem_fun и bind1st:

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

Вызов mem_fun создает новый объект функции, который принимает два аргумента - a Car* действовать как получатель и Wheel, затем вызывает put с первым параметром в качестве получателя и вторым параметром в качестве аргумента.Вызов bind1st затем блокирует объект-получатель как первый параметр этой функции на месте.

Однако, я думаю, вам нужно будет сделать одно небольшое изменение в этом коде, чтобы заставить его работать.Адаптер bind1st не очень хорошо работает с функциями, которые принимают свои аргументы по константной ссылке, поэтому может необходимо изменить put, чтобы он принимал Wheel по значению, а не по ссылке.

3 голосов
/ 10 января 2011

Вы можете использовать mem_fun_ref: см. здесь .

mem_fun_ref должно работать в вашем случае, когда у вас есть вектор объектов:

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

Обратите внимание, чтоПриведенный выше пример меняет put, чтобы стать членом Wheel, а не Car.Это должно дать вам представление о том, как его использовать.

Используйте mem_fun, если у вас есть вектор указателей на объект

1 голос
/ 10 января 2011

Конечно, вы можете просто написать свой собственный эквивалент boost :: mem_func. У TR1 тоже есть. Это немного повторяется, если вы хотите увеличить количество аргументов, но не концептуально сложно.

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

Прошло много времени с тех пор, как я написал подобный код, так что, возможно, это будет немного не так. Но это суть этого. Так сложно написать пример использования без использования лямбды.

...