2014-10-03 5 views
2

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

Итак, скажем, у меня есть класс Event. Я бы хотел, чтобы у него была переменная time и указатель функции/переменная/магическая функция functionToExecuteAtTime, которая позволяет передавать любую старую функцию этому классу.

Также я хотел бы, чтобы события проводились в очереди приоритетов, которая упорядочивает события по порядку времени и выполняет функции, которые они «переносят». Но забыть об этом на текущий

Что-то вроде этого ...

class Agent 
{ 
    public: 

    int id; 
    float cash; 

    Agent::Agent 
    { 
     cash = 100; 
    } 
} 

class uberSystem 
{ 
    public: 

    float assets; 
    int supplyOfDeadlyPoison; 
    float poisonCost; 

    std::vector<Agent> agents; 

    uberSystem::uberSystem 
    { 
     assets = 100000; 
     supplyOfDeadlyPoison = 100000; 
     poisonCost = 8; 

     for(int i = 0; i < 100; i++) 
     { 
     Agent newAgent; 
     newAgent.id = i; 
     agents.push_back(newAgent) 
     } 
    } 
}; 


class Event 
{ 
    public: 

    int time; 
    SOMETHING_THAT_LETS_ME_HOLD_FUNCTIONS myFunction; 

    Event::Event(int t, SOMETHING_THAT_LETS_ME_HOLD_FUNCTIONS func) 
    { 
     time = t; 
     myFunction = func; 
    } 
} 

int uselessFunction() 
{ 
    return 42; 
} 

void buyPoisonAndKillAgent(Agent &myAgent, uberSystem &mySystem)//obviously not good... 
{ 
    myAgent.cash -= mySystem.poisonCost; 
    mySystem.assets += mySystem.poisonCost; 
    mySystem.agents.erase(mySystem.agents.begin()+myAgent.id); 
    mySystem.supplyOfDeadlyPoison -= 1; 
} 


int main() 
{ 

    uberSystem newSystem; 
    // Event newEvent(100, uselessFunction());//make a new event 
    Event newEvent(100, buyPoisonAndKillAgent(newSystem.agents[5], newSystem)); 
    newEvent.myFunction;//run the bloody function 
    return 0; 
} 

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

О, и, видимо, у меня есть std::function, доступный в конце концов ... Я не был в каменном веке!

Спасибо!

+0

Как насчет [std :: deque >] (http://en.cppreference.com/w/cpp/container/deque)? –

+1

std :: function может это сделать, я предлагаю вам избежать указателей на функции. :) – Melkon

+0

Является ли «время» в реальном времени или моделируется? Или он просто используется для заказа событий? – MatthiasB

ответ

2

Вы можете иметь базовый класс Event (как это было предложено @EdHeal), а затем имеют шаблонный подкласс хранения вашей указатель функции:

class Event { 
public: 
    int time; 
    Event(int t) : time(t) {} 
    virtual ~Event(){} 
    virtual void myFunction() = 0; 
}; 

template<typename TFunc> 
class TEvent : public Event { 
public: 
    TFunc func; 
    TEvent(int t, TFunc f) : Event(t), func(f) {} 
    void myFunction() { func(); } 
}; 

template<typename TFunc> 
auto_ptr<Event> make_event(int time, TFunc func) { 
    return std::auto_ptr<Event>(new TEvent<TFunc>(time,func)); 
} 

С функцией хелперов make_event легко вызвать и выводит тип автоматически:

void useless() {std::cout << "Func A";} 
struct functor { 
    void operator()() {std::cout << "Functor B";} 
}; 

struct paramFunctor { 
    paramFunctor(int x, double y): result(0), m_x(x), m_y(y){} 

    void operator()() { 
    std::cout << "Params: x:" << m_x << ", y:" << m_y << "\n"; 
    } 
    long long result; 
private: 
    int m_x; 
    double m_y; 
}; 

int main() { 
    auto_ptr<Event> e1 = make_event(10,useless); 
    auto_ptr<Event> e2 = make_event(100,functor()); 
    auto_ptr<Event> e2 = make_event(100,paramFunctor(1,2.0)); 

    // your code goes here 

    e1->myFunction(); 
    e2->myFunction(); 
    e3->myFunction(); 

    return 0; 
} 

конечно, если есть доступ к C++ 11 (или TR1, или повышения) нет необходимости все это вообще (как описывают другие ответы)

+0

Не могли бы вы использовать умные указатели? :) –

+0

@ MatthieuM. Я бы хотел, но вопрос просил камень - preC++ 11 решение;) – MatthiasB

+0

Итак? 'std :: auto_ptr' и' boost :: scoped_ptr' отлично совместимы с C++ 03. 'boost :: shared_ptr' там тоже работал. Только STD :: unique_ptr стало возможным благодаря новым возможностям C++ 11 (в частности, переместить семантику). –

1

Почему бы не сделать это

class Event { 
    private: 
     int time; 
    public: 
     Event(int t) : time(t) { } 
     virtual void DoEvent() = 0; 
}; 

class MyEVent: public Event { 
    public: 
     MyEvent(int t) : Event(t) { } 
     void DoEvent() { std::cout << "Event called" << std::endl; 
}; 

затем

int main() { 

    MyEvent e(100); 
    e.DoEvent(); 
    return 0; 
} 

Это кажется проще, и вы имеете роскошь добавлять любые данные, необходимые для этого мероприятия.

Для списка вы используете Event указатели, например. Event *e = new MyEvent(100)

+0

Выглядит неплохо на самом деле! – Argh

1

Самый простой способ удержания общей функции или закрытия - использовать std::function; в отсутствие C++ 11 boost::function - хороший заполнитель для него.

Это дает:

class Event { 
public: 
private: 
    std::time_t time; 
    boost::function<void()> function; 
}; // class Event 

Обратите внимание, что подпись функции должен быть уточнено: void() функция не принимает никаких аргументов и не возвращая ничего.

Также обратите внимание, что вы можете произвольные предикаты, классы-функторы или lambdas, если один из operator() соответствует ожидаемой сигнатуре.

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