How to implement a simple event queue?

2020-06-26 03:04发布

So, I did a reasonable amount of googling first, but all of the solutions seem unreasonably complex. So, I thought I'd ask here to see if this task really requires the kind of approach I've been encountering...

So, say I have an Event class. I would like it to have a time variable, and a functionToExecuteAtTime function pointer / variable / magic piece of code that lets me pass any old function to this class.

Also I would like the events held in a priority queue that arranges the events in order of time and executes the functions they are "carrying". But forget about this for now

Something like this...

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

Okay, so that looks like extremely wishful thinking now that I type it. So, how can I achieve this? Is function pointers the way to go? Or is there some better way that I have somehow managed to not find yet?

Oh, and apparently I do have std::function available after all... I was not in the stone age all along!

Thanks!

标签: c++ events
3条回答
爱情/是我丢掉的垃圾
2楼-- · 2020-06-26 03:37

Why not do this

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

then

int main() {

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

This seems simpler and you have the luxury of adding whatever data is required for the event.

For a list you use Event pointers e.g. Event *e = new MyEvent(100)

查看更多
来,给爷笑一个
3楼-- · 2020-06-26 03:40

The simplest way to hold a generic function or closure is to use std::function; in the absence of C++11 boost::function is a good placeholder for it.

This yields:

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

Note that the signature of the function need be precised: void() is a function taking no argument and returning nothing.

Also, note that you can arbitrary predicates, functor classes or lambdas, as long as one of the operator() matches the expected signature.

查看更多
孤傲高冷的网名
4楼-- · 2020-06-26 03:56

You can have a Base class Event (as proposed by @EdHeal) and then have a templated subclass storing your function pointer:

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

With the helper function make_event it is easy to call and deduces the type automatically:

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

Of course, if there is access to C++11 (or TR1, or boost) there is no need for all this at all (as other answers describe)

查看更多
登录 后发表回答