2013-05-19 2 views
1

Я пишу класс, где мне бы хотелось иметь некоторые методы-члены, которые имеют некоторые данные, связанные с ними, в частности, какие механические системы робота, которым они требуют использования. Я думал, что я мог бы написать их как функторов, что-то вроде этого (это не мой фактический код):Личные члены-функторы для класса C++

class MyRobot : public Robot { 
public: 
    MyRobot(); 
    void runRobot(); 
private: 
    Command do_something_, 
      do_another_thing_; 
} 

А затем инициализировать do_something_ с лямбда в конструкторе, как:

do_something_([] { 
    do_first_thing(); 
    do_second_thing(); 
}); 

А потом сказать do_something_, какие требования он имеет:

do_something_.requires(system_a); 
do_something_.requires(system_b); 

И в runRobot() я бы сказал планировщик робота для выполнения команд:

void MyRobot::runRobot() { 
    scheduler.add(do_something_); 
    scheduler.add(do_another_thing_); 
} 

Но я пришел к выводу, что, поскольку число команд растет, тем менее управляемый конструктор MyRobot будет, так как каждая команда будет ее тело определена там. Я могу сделать соответствующий частный метод для каждой команды и инициализировать их указателем на функцию вместо лямбда, но это просто кажется более запутанным. Я мог бы также подкласса Command для каждой конкретной команды и, таким образом, иметь тело и требования в отдельном файле для каждого из них, но это выглядит как много накладных расходов для довольно простой задачи. Есть ли хороший способ сделать это, о котором я не знаю?

+0

Почему бы не иметь их как простые функции-члены, и связать нужные им данные в точке, где вы передаете их в планировщик (либо через 'станд :: bind' или просто простой лямбда)? – Xeo

+1

Несвязанные: не используйте имя «функторы» для объектов функций C++. Я знаю, что он используется многими людьми; Я прошу всех избегать этого. Это неправильное название. Слово имеет хорошо установленное значение в CS и математике, и каждый будет лучше, если мы не будем его использовать для чего-то совершенно не связанного. –

+1

@ н.м. Я знаю, какие функторы находятся в контексте теории категорий, но учитывая, что «функтор» является наиболее часто используемым термином в контексте C++, я буду продолжать его использовать. –

ответ

0

Вы можете определить класс Command, чтобы принять std::function и список инициализаторов «требований», как они есть у вас. Затем вместо использования lambdas вы можете сделать do_something и do_another_thing свои собственные частные функции-члены, поэтому вам не нужно определять их тела в конструкторе. Наконец, в конструкторе вы можете построить экземпляры Command, привязав частные функции-члены с этим указателем текущего экземпляра MyRobot, а также предоставив им список требований. Объекты Command должны иметь возможность изменять личное состояние экземпляров MyRobot. Ниже приведен пример. Также см. example output.

#include <functional> 
#include <iostream> 
#include <vector> 

enum System { SYS_A, SYS_B, SYS_C }; 

class Command { 
public: 
    typedef std::function<void()> FuncType; 

    Command(FuncType func, std::initializer_list<System> requirements) 
    :func_(func), requirements_(requirements) { } 

    void operator()() { 
    std::cout << "Executing Command:" << std::endl; 
    for (System s : requirements_) 
     std::cout << " REQUIRES " << static_cast<int>(s) << std::endl; 
    func_(); 
    } 

private: 
    FuncType   func_; 
    std::vector<System> requirements_; 
}; 

class Scheduler { 
public: 
    void add(Command c) { 
    c(); 
    } 
}; 

class Robot { 
public: 
    Robot() 
    :do_something_ (std::bind(&Robot::do_something, this),  {SYS_A, SYS_B}), 
    do_another_thing_(std::bind(&Robot::do_another_thing, this), {SYS_A, SYS_C}) { } 

    void runRobot() { 
    s_.add(do_something_); 
    s_.add(do_another_thing_); 
    } 

private: 
    void do_first_thing() { std::cout << " FIRST THING!" << std::endl; } 
    void do_second_thing() { std::cout << " SECOND THING!" << std::endl; } 
    void do_third_thing() { std::cout << " THIRD THING!" << std::endl; } 

    void do_something()  { do_first_thing(); do_second_thing(); } 
    void do_another_thing() { do_first_thing(); do_third_thing(); } 

    Command do_something_; 
    Command do_another_thing_; 
    Scheduler s_; 
}; 

int main(int, char**) { 
    Robot().runRobot(); 
} 
Смежные вопросы