Вызовите функции-члены элементов контейнера с помощью for_each? - PullRequest
4 голосов
/ 13 мая 2009

Запутанный заголовок, надеюсь, какой-то код прояснит:

struct MyNestedType {
    void func();
};

struct MyType {
    MyNestedType* nested;
}

std::vector<MyType> vec;

// ... populate vec

// I want something approximating this line, but that doesn't use made-up C++!
std::for_each(vec.begin(), vec.end(), std::mem_fun_ref(&MyType::nested->func));

Так что в основном я хочу вызвать метод для каждого элемента контейнера, но на самом деле это не метод типа, это какой-то метод для отдельного типа ... Я знаю, что мог бы написать объект функции для передачи «вызов, но есть несколько методов, которые я хотел бы вызвать, и это станет грязным.

Есть идеи?

Ответы [ 6 ]

6 голосов
/ 13 мая 2009

Почему бы вам просто не использовать простой цикл for?

for(vector<MyType>::iterator i = vec.begin(); i != vec.end(); ++i)
    i->nested->func();

В качестве альтернативы, вы можете использовать лямбда-выражения или boost :: foreach

FOREACH(MyType x, vec)
    x.nested->func();

Вы можете создать свое выражение с помощью binders и mem_funs, но это будет очень запутанно и запутанно! Нет смысла помещать все в одну строку std :: foreach.

3 голосов
/ 13 мая 2009

Вы можете использовать такой функтор

template <typename T, T* MyType::* TMember, void (T::* TNestedMember)() >
struct Caller {
    Caller() {
    }

    template <typename TObject>
    void operator()(TObject object) {
        (object.*TMember->*TNestedMember)();
    }
};

Чтобы решить вашу проблему

struct MyNestedType {
    MyNestedType(int a):
        a_(a){
    }
    void func() {
        std::cout << "MyNestedType::func " << a_ << std::endl;
    }
    void foo() {
        std::cout << "MyNestedType::foo " << a_ << std::endl;
    }
    int a_;
};
struct MyType {
    MyNestedType* nested;
};

int main()
{
    std::vector<MyType> vec;

    std::auto_ptr<MyNestedType> nt1(new MyNestedType(2));
    std::auto_ptr<MyNestedType> nt2(new MyNestedType(5));
    MyType t1 = {nt1.get()};
    MyType t2 = {nt2.get()};

    vec.push_back(t1);
    vec.push_back(t2);

    std::for_each(vec.begin(), vec.end(), 
                  Caller<MyNestedType, &MyType::nested, &MyNestedType::func>());
    std::for_each(vec.begin(), vec.end(), 
                  Caller<MyNestedType, &MyType::nested, &MyNestedType::foo>());
}
2 голосов
/ 13 мая 2009

Да, для этого можно использовать boost::bind, но это становится грязным. Пожалуйста, используйте @ Dario's Boost для каждого способа, но вот boost::bind для полноты

std::for_each(vec.begin(), vec.end(), 
    boost::bind(&MyNestedType::func, boost::bind(&MyType::nested, _1)));

Во всяком случае, так получилось, что мы даже не получили хорошую строчку с этим:)

2 голосов
/ 13 мая 2009

Если вы хотите использовать for_each, вам нужен функтор.

struct CallMyFunc
{
    void operator()(MyType& obj)    {   obj.nested->func();}
};


std::for_each(vec.begin(), vec.end(), CallMyFunc());

В качестве альтернативы я бы использовал синтаксис boost :: FOREACH, описываемый как:

Dario: Вызовите функции-члены элементов элементов контейнера с помощью for_each?

2 голосов
/ 13 мая 2009

Может быть, вы могли бы добавить func () в struct MyType ():

void func(...) {
   nested->func(...);
}

Таким образом, у вас не будет отдельного функтора адаптера, а вместо этого будет агрегирование внутри типа-обертки, т. Е. Довольно обычный метод ООП.

0 голосов
/ 13 мая 2009

Как насчет использования Boost's transform_iterator?

...