Solved

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

Posted on 2014-12-23
11
272 Views
Last Modified: 2015-01-06
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
0
Comment
Question by:sean-keys
  • 7
  • 2
  • 2
11 Comments
 
LVL 86

Assisted Solution

by:jkr
jkr earned 250 total points
ID: 40515717
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
 

Author Comment

by:sean-keys
ID: 40515747
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
 

Author Comment

by:sean-keys
ID: 40515750
ActionClass::MemberName  could it be that easy...
0
Ransomware: The New Cyber Threat & How to Stop It

This infographic explains ransomware, type of malware that blocks access to your files or your systems and holds them hostage until a ransom is paid. It also examines the different types of ransomware and explains what you can do to thwart this sinister online threat.  

 

Author Comment

by:sean-keys
ID: 40515757
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
 
LVL 86

Expert Comment

by:jkr
ID: 40515949
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
 

Author Comment

by:sean-keys
ID: 40515979
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
 
LVL 33

Accepted Solution

by:
sarabande earned 250 total points
ID: 40521896
//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
 

Author Comment

by:sean-keys
ID: 40524132
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
 

Author Comment

by:sean-keys
ID: 40524586
Maybe inheritance is the answer...
0
 
LVL 33

Expert Comment

by:sarabande
ID: 40524825
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
 

Author Closing Comment

by:sean-keys
ID: 40534035
It's really a design problem on my part. Thanks guys, I have enough info to roll a *decent solution.
0

Featured Post

Netscaler Common Configuration How To guides

If you use NetScaler you will want to see these guides. The NetScaler How To Guides show administrators how to get NetScaler up and configured by providing instructions for common scenarios and some not so common ones.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
FMX StringGrid1->Canvas->FillRect Problem 3 153
Find Visual Studio Tools 2 103
FMX TCameraComponent Problem 2 70
max float value 3 41
Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
Written by John Humphreys C++ Threading and the POSIX Library This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.   [s…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

777 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question