Link to home
Start Free TrialLog in
Avatar of sean-keys
sean-keys

asked on

Specify call-back member function in c++ templated class constructor

I created the following templated c++ class

template<class ActionClass> class Timer {
public:

	Timer(uint32_t initialDelayMS, uint32_t intervalMS, ActionClass* action) :	TimerCallback(action), alarmCounter(0) { ....

Open in new window


	/**
	 * The signal handler function with extended signature
	 */
	static void alarmFunction(int sigNumb, siginfo_t *si, void *uc) {
		// get the pointer out of the siginfo structure and assign it to a new pointer variable
		Timer *ptrTimer = reinterpret_cast<Timer *>(si->si_value.sival_ptr);
		ptrTimer->TimerCallback->TimerCallBack();
	}

Open in new window


Is there a way so that I can specify which member function to call back? Like this:
ptrTimer->TimerCallback->SpecifidMemberFunctionFromConstructor 

Open in new window


Thanks,
Sean
SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of sean-keys
sean-keys

ASKER

Awesome, my only issue is how to make
Timer<ActionClass>::MemberName;

Open in new window

into a ctor parameter... Sorry been away from c++ for years now.
ActionClass::MemberName  could it be that easy...
Timer(uint32_t initialDelayMS, uint32_t intervalMS, ActionClass* action, ActionClass::MemberName) :      TimerCallback(action), alarmCounter(0) {

src/inc/Timer.h:26:88: error: 'ActionClass::MemberName' is not a type

Not quite :)
You should be able to exchange 'SpecifidMemberFunctionFromConstructor' for that name if I'm not too confused about the setup (hint: the more code, the better)
I'll do some digging thx.

FWIW
template<class ActionClass> class Timer {

	typedef void(ActionClass::*memberFunction)(); //TODO consider passing a function ptr rather than a class

public:

	Timer(uint32_t initialDelayMS, uint32_t intervalMS, ActionClass* action, memberFunction MemberName) :	TimerCallback(action), alarmCounter(0) {

		uint64_t delay = initialDelayMS * NANO_FACTOR;
		uint64_t interval = intervalMS * NANO_FACTOR;

		this->timerSpecs.it_value.tv_sec = initialDelayMS / MILI_FACTOR;
		this->timerSpecs.it_value.tv_nsec = delay - ((initialDelayMS / MILI_FACTOR) * NANO_FACTOR * MILI_FACTOR);
		// and then all 3 seconds a timer alarm
		this->timerSpecs.it_interval.tv_sec = intervalMS / MILI_FACTOR;
		this->timerSpecs.it_interval.tv_nsec = interval - ((intervalMS / MILI_FACTOR) * NANO_FACTOR * MILI_FACTOR);

		// Clear the sa_mask
		sigemptyset(&this->SignalAction.sa_mask);
		// set the SA_SIGINFO flag to use the extended signal-handler function
		this->SignalAction.sa_flags = SA_SIGINFO;

		// Assign sigaction method
		this->SignalAction.sa_sigaction = Timer::alarmFunction;

		// Define sigEvent
		// This information will be forwarded to the signal-handler function
		memset(&this->signalEvent, 0, sizeof(this->signalEvent));
		// With the SIGEV_SIGNAL flag we say that there is sigev_value
		this->signalEvent.sigev_notify = SIGEV_SIGNAL;
		// Now it's possible to give a pointer to the object
		this->signalEvent.sigev_value.sival_ptr = (void*) this;
		// Declare this signal as Alarm Signal
		this->signalEvent.sigev_signo = SIGALRM;

		// Install the Timer
		if (timer_create(CLOCK_REALTIME, &this->signalEvent, &this->timerID) != 0) {
			perror("Could not create the timer");
		}

		// Finally install tic as signal handler
		if (sigaction(SIGALRM, &this->SignalAction, NULL)) {
			perror("Could not install new signal handler");
		}

		//specifiedCallBack = ActionClass::MemberName;

	}

	virtual ~Timer(){};

	void start() {
		if (timer_settime(this->timerID, 0, &this->timerSpecs, NULL) == -1) {
			perror("Could not start timer:");
		}
	}

	/**
	 * The signal handler function with extended signature
	 */
	static void alarmFunction(int sigNumb, siginfo_t *si, void *uc) {
		// get the pointer out of the siginfo structure and assign it to a new pointer variable
		Timer *ptrTimer = reinterpret_cast<Timer *>(si->si_value.sival_ptr);
		ptrTimer->TimerCallback->TimerCallBack();
	}

	// Stored timer ID for alarm
	timer_t timerID;
	// Signal blocking set
	sigset_t SigBlockSet;
	// The according signal event containing the this-pointer
	struct sigevent signalEvent;
	// Defines the action for the signal -> thus signalAction <img src="http://quirk.ch/wordpress/wp-includes/images/smilies/icon_wink.gif" alt=";-)" class="wp-smiley">
	struct sigaction SignalAction;
	// The itimerspec structure for the timer
	struct itimerspec timerSpecs;

private:
	ActionClass* TimerCallback;
	void (Timer<ActionClass>::*specifiedCallBack) ();

	int alarmCounter;
	void DefaultAlarmFunction() {
		this->alarmCounter++;
		std::cout << "Timer expired but you did not assign an action!! Signal occurred. Count=" << this->alarmCounter
				<< std::endl;
	}
};

Open in new window

ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi Sara
in my opinion your current issues are not because of the complexity of the Problem but of the strangeness of your design.
Indeed! I'm a C guy who is just getting back into OOP. Essentially want I want to do is create a timer instance with parameters that determine interval and what call-back to execute. The issue is that the call-back needs to access member data, so I  don't really see an easy way to use a static function.

I have a core program with about 10 functions that need to be executed at specified intervals. These are all member functions of instantiated classes, that need to be run. I guess maybe what I could do is remove all the template stuff and create a static member function for each class that calls the timed tasks via an instance pointer etc. At least that would simplify the time class itself.

Thoughts?

Thanks,
Sean
Maybe inheritance is the answer...
Maybe inheritance is the answer...
yes, probably. you already have a timer class. if you allow to derive from it you could make all the common parameters  members of the timer baseclass; special parameters may be members of the derived class. instead of passing a callback function pointer, the timer baseclass may have a virtual function which you could overload in the derived class. additionally, you would use a timer manager class which is a singleton. timer manager has functions addTimer, killTimer and would run a thread to watch over the active timers. if a timer was due, the manager would invoke the callback by a virtual call.

Sara
It's really a design problem on my part. Thanks guys, I have enough info to roll a *decent solution.