Solved

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

Posted on 2014-12-23
11
263 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
Comment Utility
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
Comment Utility
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
Comment Utility
ActionClass::MemberName  could it be that easy...
0
 

Author Comment

by:sean-keys
Comment Utility
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
Comment Utility
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
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 

Author Comment

by:sean-keys
Comment Utility
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 32

Accepted Solution

by:
sarabande earned 250 total points
Comment Utility
//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
Comment Utility
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
Comment Utility
Maybe inheritance is the answer...
0
 
LVL 32

Expert Comment

by:sarabande
Comment Utility
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
Comment Utility
It's really a design problem on my part. Thanks guys, I have enough info to roll a *decent solution.
0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

771 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

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now