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
sean-keysAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jkrCommented:
Yes, there is, see http://www.newty.de/fpt/index.html ("The Function Pointer Tutorials") and http://www.newty.de/fpt/callback.html#member ("3.5  How to Implement a Callback to a non-static C++ Member Function ?"). You can also use a more direct approach like

template<class ActionClass> class Timer {
public:

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

// ...

// declare a member pointer called 'SpecifidMemberFunctionFromConstructor'
// as a member of your class
void (Timer<ActionClass>::*SpecifidMemberFunctionFromConstructor)();
// populate it in your ctor like 
// SpecifidMemberFunctionFromConstructor = Timer<ActionClass>::MemberName;
.
// ...
};
                                  

Open in new window


and call it like

(ptrTimer->TimerCallback->*SpecifidMemberFunctionFromConstructor)() 

Open in new window

0
sean-keysAuthor Commented:
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.
0
sean-keysAuthor Commented:
ActionClass::MemberName  could it be that easy...
0
Cloud Class® Course: Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

sean-keysAuthor Commented:
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 :)
0
jkrCommented:
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)
0
sean-keysAuthor Commented:
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

0
sarabandeCommented:
//TODO consider passing a function ptr rather than a class
a member function pointer requires a weird syntax since it requires a pair of object and function pointer to be valid. because of that i don't know any real concepts where pointers to member functions were playing a major role.

in your question it seems that a static member function which is equivalent to a global non-member function should be passed to a timer class as argument. for that a template class seems to be an overkill as you could pass an arbitrary class to the timer which may provide any complex interface, plus a function pointer where the function also could do anything you want. in my opinion your current issues are not because of the complexity of the Problem but of the strangeness of your design. you should see that a template type is not a variable at run-time but must be determined at compile time. so templates make sense for container classes which could store different types with one code. a template class which is only used for one type creates many efforts with no benefit. using member function pointers with the template class will make usage to a nightmare.

so i would recommend to defining the timer class as a normal class which uses a function pointer as member that is not a member function pointer but a normal c function pointer:

typedef void (*AlarmFunction)(int , siginfo_t *, void *);
class Timer
{
     ...
     Timer(AlarmFunction cb) : callback(cb) {}
     AlarmFunction callback;

Open in new window


of course you may add more members which also could serve as arguments for the callback.

Sara
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
sean-keysAuthor Commented:
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
0
sean-keysAuthor Commented:
Maybe inheritance is the answer...
0
sarabandeCommented:
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
0
sean-keysAuthor Commented:
It's really a design problem on my part. Thanks guys, I have enough info to roll a *decent solution.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.