1

I would love create javascript's setTimeout and setInterval like functionality for c++ (without boost). What I would like to achieve: A base class which could call its sub-classed member variables at a repeated or after a single delay.

I have an update function already and time elapsed functionality. I have also found how to pass a member function pointer to the base class and trigger that function using:

class BaseClass {
public:
     template <class object>
     void triggerNow(object *obj, void (object::*func)()) {
          ((obj)->*(func))();
     }

} 

class SubClass : public BaseClass {
public:
    void update() {
         triggerNow(this, &SubClass::worked)
    }
    void worked() {
         cout << "worked!";
    }
}

The problem I currently face is how to store object *obj and void (object::*func)() in a vector (or other container). I am only just figuring out templates...

How can I store the two templated parameters of triggerNow in a vector? Once I can figure this out, I can create my setTimeout and setInterval!

3
  • 1
    You can declare an std::vector<void (object::*)()> theVector instance variable, then have a look at how Foundation's legendary NSTimer class does the thing (though that is Objective-C, the C parts will match :) Commented Oct 13, 2012 at 18:28
  • @Ross: how hard are your timer requirements ? do you expect to be able to do something else in the mean time ? (ie, multi-threading at play...) Commented Oct 13, 2012 at 19:29
  • Timing/timer requirement are not a problem. Commented Oct 14, 2012 at 1:36

2 Answers 2

2

No comment on the timing functionality yet.

However, since you are using parent and base classes, I would suggest using polymorphism, rather than a template member function.

class BaseClass {
    public:
        virtual void triggerMe() = 0;

 };

class SubClass1 : public BaseClass {
    public:
        virtual void triggerMe()
        {
            //real code, do something
        }

 };

class SubClass2 : public BaseClass {
    public:
        virtual void triggerMe()
        {
            //real code, do something else
        }

 };

Then you can just have a vector of pointers to BaseClass:

vector<BaseClass*> objects;

objects.push_back(new SubClass1);
objects.push_back(new SubClass2);

for (auto it = objects.begin(); it != objects.end(); it++)
{
    it->triggerMe();
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your answer. But, correct me if I am wrong, this would have little advantage over BaseClass having virtual void triggerMe()=0?
1

In order to store object* and object::*func in a vector you can do it like this:

struct Callable
{
  virtual ~Callable () {};
  virtual void operator()() = 0;
};

template <class Object>
struct TemplateCallable : public Callable
{
  typedef void (Object::*MemberFunction)();

  TemplateCallable(Object* obj, MemberFunction mem_fun)
     : _object(obj),
       _mem_fun(mem_fun)
  {}

  void operator() ()
  {
    _object->*_mem_fun();
  }

  Object* _obj;
  MemberFunction _mem_fun;
};

Now you can store them as Callable's in a std::vector, because the templated version is derived from Callable. If you store pointers in a std::vector<> though you need to remember to delete them at some point.

So will get something like this:

class TimerSomething
{
   template <class Object>
   void registerCallback (Object* obj, void (Object::*MemFun)())
   {
     _callbacks.push_back(new TemplatedCallback<Object>(obj, mem_fun));
   }

   void triggerAll ()
   {
     for (std::vector<Callable*>::iterator iter = _callbacks.begin();
          iter != _callbacks.end(); ++iter)
     {
       (**iter)();
     }
   }

   std::vector<Callable*> _callbacks;
};

4 Comments

@MatthieuM. indeed std::function or boost::function really helps. One ends up writing a lot of code when neither boost nor C++11 is available :)
Thanks will try this! Yes, boost or C++11 would help, but I am looking for a/the vanilla c++ solution.
virtual void operator() = 0; has a compile time error of 'operator()' cannot be the name of a variable or data member, but I added (for want of a better name) virtual void doIt()=0. Brilliant, thanks!
@Ross that is because the call operator should actually be virtual void operator() () = 0, I forgot one pair of braces, will fix now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.