2012-03-15 2 views
0

Можно ли использовать std :: for_each или что-то еще подобное?
Как использовать std :: for_each?

#include <list> 
#include <algorithm> 

// Class declaration 
// 
struct Interface 
{ 
    virtual void run() = 0; 
}; 

struct A : public Interface 
{ 
    void run() { std::cout << "I run class A" << std::endl; } 
}; 

struct B : public Interface 
{ 
    void run() { std::cout << "I run class B" << std::endl; } 
}; 

// Main 
// 
int main() 
{ 
    // Create A and B 
    A a; 
    B b; 

    // Insert it inside a list 
    std::list<Interface *> list; 
    list.push_back(&a); 
    list.push_back(&b); 

    // Then execute a func with for_each without recreate a func which call Interface::run() 
    std::for_each(list.begin(), list.end(), run); 

    return 0; 
} 

Edit: Мой вопрос: Как я могу позвонить каждый запустить() функцию-член внутри цикла с использованием алгоритма или более просто C++ пути без использования итератора ...

+0

'ИНТЕРФЕЙС = новый A; 'Это даже не компилируется. Что именно вы пытаетесь сделать? –

+0

Здесь нет никаких вопросов –

+0

Извините, я написал небольшой код, чтобы показать только то, что я хочу сделать. В основном я хочу вызвать функцию-член, выполняемую внутри цикла, используя for_each или что-то еще. Я знаю, что могу использовать итератор, но я спрашиваю себя, есть ли другой способ. – klefevre

ответ

8

Вы можете сделать это с помощью std::mem_fun:

std::for_each(list.begin(), list.end(), std::mem_fun(&Interface::run)); 
+1

Вау, я никогда не знал о 'mem_fun'. +1 –

+5

'std :: mem_fn' - правильная функция с C++ 11,' std :: mem_fun' устарела, поскольку она работает только для функций аргументов 1 (или 2?). – Xeo

+1

Вы также можете использовать 'std :: bind' в C++ 11 –

1

Нет, необходимо создать функцию-обертку, которая вызовет run() на любой объект, переданный в него. У C++ нет такой динамической отправки, которая позволит вам использовать строку для ссылки на функцию и искать ее во время выполнения - то, что вызывается в for_each, должно быть одной и только одной функцией по одному адресу, а не полиморфная функция.

Вам не нужно создавать функцию-обертку для каждого объекта: у вас ее просто есть, и она вызывается повторно и передается в объекте. Тогда вы называете запуска() на переданному в объекте, и полиморфизм делает все остальное:

void wrapper(Interface* obj) 
{ 
    obj->run(); 
} 

std::for_each(list.begin(), list.end(), wrapper); 
+0

Конечно, я могу это сделать, но что, если у меня есть функция 30 членов? Я должен создать 30 оберточных функций ...? Я не думаю, что это хороший способ просто позвонить одному func =/Что вы думаете? – klefevre

+0

@Matt Вы будете хранить вещи в списке как указатели, а не значения, поэтому подпись для оболочки должна быть 'void wrapper (Interface * obj)' (а также не 'const', потому что' run' не 'const') –

+0

@ kl94 no вы просто вызываете 30 функций-членов в обертке один за другим. Затем эти вызовы будут выполняться по каждому элементу в списке. –

2

Вероятно, самым простым способом было бы использовать функцию лямбда :

boost::for_each(list, [](Interface* i){ i->run(); }); 

других варианты включают в себя:

boost::for_each(list | boost::adaptors::indirected, std::mem_fn(&Interface::run)); 

и

boost::for_each(
    list | boost::adaptors::indirected, 
    std::bind(&Interface::run, std::placeholders::_1)); 
+0

Спасибо за ваше участие, но я не использую boost в этом проекте. Я, несмотря ни на что, оставил тебя в живых. – klefevre

1

Принимая пример Мэтта, но делает его родовое:

class wrapper : public std::unary_function(Interface*, void) { 
    void (Interface::*pmf)(); 
public: 
    wrapper(void (Interface::*pmf)()) : pmf(pmf) { } 
    operator()(Interface* intf) { intf->*pmf(); } 
}; 

std::for_each(ist.begin(), list.end(), custom_wrapper(&Interface::run)); 

Если вам необходимо поддерживать аргументы, проистекают из std::binary_function(Interface*, T, void) и хранить T вместе pmf

Смежные вопросы