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
C++

Avatar of undefined
Last Comment
sean-keys

8/22/2022 - Mon
SOLUTION
jkr

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
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.
sean-keys

ASKER
ActionClass::MemberName  could it be that easy...
sean-keys

ASKER
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 :)
This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23
jkr

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)
sean-keys

ASKER
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
sarabande

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
sean-keys

ASKER
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
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
sean-keys

ASKER
Maybe inheritance is the answer...
sarabande

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
sean-keys

ASKER
It's really a design problem on my part. Thanks guys, I have enough info to roll a *decent solution.
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy