LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 10-23-2008, 07:20 AM   #1
lali.p
Member
 
Registered: Jan 2007
Distribution: Slackware 11.0
Posts: 141

Rep: Reputation: 16
Function pointer and functors problem


Hi

Sorry for the stupid heading of the thread, i could not think any better.

I am having a doubt about function pointers and functors. I know that the signatures of a function pointer and a pointer to a class member function are different. However signature of a global function and signature of a static class function are compatible.

Here is what i want to achieve:

There are 2 unrelated classes say A and B ( they are unrelated and hence i don't want to make them part of any inheritance structure)

I have written a timer class in which i can register multiple timers, it takes a timeout value and a function pointer that would be invoked when the timer times out i.e basically i want a callback mechanism on timeout. So internally the timer is using a queue to store all these function pointer and all these function pointers have signature void (*ptr)( );

So the queue would be like:

Code:
typedef void (*ptr)( );
queue<ptr> timer_queue;
The problem is i want to invoke the member function of classes A and B when a timer expires so that i can change the state of object of class A or B.

Let me make it clear( i really suck in communication, sorry for that)

Code:
class A
{
	public:
		A( ):a(5)
		{
		}
		void timerExpired( )
		{
			cout<<a;
		}

	private:
	int a
};

class B
{
	public:
		B():name("JOHN")
		{
		}
		void timerExpired( )
		{
			cout<<name;
		}
	private:
		string name;
};
So i want a timer that can help me code the below code the following code may not be syntactically correct )

Code:
Timer timer;
A obj_of_a;
B obj_of b
// please remember that timer uses a queue of function pointers
timer.registerTimer(A::timerExpired,6)// expires after 5 seconds

timer.registerTimer(B::timerExpired,2) // expires after 2 seconds

Problem is that these two functions are not static and if i make them static how would i change the state of the objects ( static functions don't have this pointer)
Is it even possible i.e to store pointers to member functions (of different classes) in a queue and invoke them.

It can be done if i make A and B derived from class C containing a virtual function timerExpired and then storing a functor instead of a function pointer but i don't want to do that as in my case A and B are not at all related.

Can it be done somehow using wrapper static functions of classes A and B ??
Please provide some hint or guidance.

Thanks a lot for your patience
Regards
lali
 
Old 10-23-2008, 11:38 AM   #2
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Quote:
Can it be done somehow using wrapper static functions of classes A and B ??
Yes, but only if you give the timer a pointer to the object as well. eg
Code:
typedef void (*ptr)( void *arg );
typedef pair<void*, ptr> callee;
queue<callee> timer_queue;

class A {
  ...
  static void callTimerExpired(void *arg);
};
void A::callTimerExpired(void *arg) {
       A *_this = (A*) arg;
       _this->timerExpired();
}

timer.registerTimer(make_pair(&obj_of_a, A::callTimerExpired),6)// expires after 5 seconds
 
Old 10-23-2008, 03:32 PM   #3
dmail
Member
 
Registered: Oct 2005
Posts: 970

Rep: Reputation: Disabled
Personally I would use an existing functor library like Loki, Boost or an implementation of C++0x. Using one of these it is possible to register any of the following function, this example uses Loki.
Code:
typedef Functor<void,NullType> ptr;
typedef queue<ptr> timer_queue;

struct foo
{
	void timeout(){}
	static void do(){}
};

struct bar
{
	void timer(){}
	void operator()(){}
};

void baz(){}

timer_queue q;
q.push_back(ptr(new foo,&foo::timeout));
q.push_back(ptr(&foo::do));
q.push_back(ptr(new bar,&bar::timer));
q.push_back(ptr(&baz));
 
Old 10-23-2008, 04:07 PM   #4
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by ntubski View Post
Yes, but only if you give the timer a pointer to the object as well. eg
Code:
typedef void (*ptr)( void *arg );
typedef pair<void*, ptr> callee;
queue<callee> timer_queue;

class A {
  ...
  static void callTimerExpired(void *arg);
};
void A::callTimerExpired(void *arg) {
       A *_this = (A*) arg;
       _this->timerExpired();
}

timer.registerTimer(make_pair(&obj_of_a, A::callTimerExpired),6)// expires after 5 seconds
void* is a terrible idea in C++. That's what templates and abstract classes are for!
Code:
#include <iostream>


struct function_wrapper
{
    virtual void function() = 0;
};


template <class Type>
class function_template : public function_wrapper
{
public:
    function_template(Type *pPointer) : pointer(pPointer) {}

    void function()
    { if (pointer) pointer->function(); }

private:
    Type *const pointer;
};


struct structure1
{
    void function()
    { std::cout << "structure1\n"; }
};

struct structure2
{
    void function()
    { std::cout << "structure2\n"; }
};


int main()
{
    structure1 one;
    structure2 two;

    function_wrapper *wrapper = NULL;

    wrapper = new function_template <structure1> (&one);
    wrapper->function();
    delete wrapper;

    wrapper = new function_template <structure2> (&two);
    wrapper->function();
    delete wrapper;
}
The code in main can be encapsulated into yet another class derived from function_wrapper so that it can encapsulate any object. This is a very reliable pattern, but one problem with it is that the name of the function must be fixed. In any case, there is absolutely no way that class1::function and class2::function can be derived from a single function pointer; you need to use something like this.
ta0kira
 
Old 10-23-2008, 08:08 PM   #5
dmail
Member
 
Registered: Oct 2005
Posts: 970

Rep: Reputation: Disabled
Whilst the code posted by ta0kira would work for this instance I would have to say it is not a nice implementation due to it not being generic enough. It is the fundamentals of how functors are done yet any change to the function signature requires a change of the base class or worst still if you have many signatures in a project then many different base "wrappers" hand coded, for example if you wanted a return type or parameters. Added to this that all functions have to be member functions and have the same name and it is reinventing a well defined wheel which good libraries with good support all ready implement.

Last edited by dmail; 10-23-2008 at 08:10 PM.
 
Old 10-23-2008, 08:31 PM   #6
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Yeah, I didn't read the thread very well I guess. I actually wrote something several years ago that did what ptr in your post does and I sort of misremembered how I did it. Regardless, it's often better to use something already built and maintained.
ta0kira
 
Old 10-24-2008, 01:16 AM   #7
lali.p
Member
 
Registered: Jan 2007
Distribution: Slackware 11.0
Posts: 141

Original Poster
Rep: Reputation: 16
Thanks for your replies, i had installed boost recently on my system. For the time being i am implementing the idea provided by ntubski as i need this thing done by the end of day. However, soon i would go through boost::function and would use that in future.


@ta0kira But don't you think that such libraries would also be using void* pointer and casting in their implementation ?
Quote:
void* is a terrible idea in C++. That's what templates and abstract classes are for!
Are templates an answer to explicit casting ?( correct me if i am wrong )

One more thing i would like to mention. I have found the boost libraries to be a source of extremely good learning material, making the life of an application programmer quite easy.Boost libraries come with documentation on how to *use* the library but no information about how it is implemented(boost after all is not meant for tutoring or mentoring)

However i would also like to learn how things are implemented( and designed ) in such expertly written libraries. I don't want to be a mere user of such libraries and so want to improve my skill by reading code written by experienced people and then compare with what i would have thought about implementing the same thing and thereby learn in the process.


Although boost libraries come with source code, if i begin reading a library say asio, it is dependent on other boost libraries like boost::system ,boost::function(i am not sure about that)
and so most of the time i get lost in details. There are no pointers as how to read code, i mean where to start first.

I can comprehend most of the code that i read except these library dependencies. Any hints on how i can tackle that problem ?

I know that learning programming is not like following a list of sequentional steps from beginning to end and is not a straight path. It takes time and patience. However if any of you has ever tried learning from code written by others, please shed some light on your experience on how to do it.

Last edited by lali.p; 10-24-2008 at 01:21 AM. Reason: grammatical error
 
Old 10-24-2008, 05:11 AM   #8
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
Here's a timer class (Timer.hpp) that I tinkered with a couple of years ago. I never used it for anything; maybe it can provide you with some ideas. (Btw, sorry for the lack of documentation; hopefully the TestTimer.cpp test-program will serve as a guide).

Timer.hpp (provides for blocking or non-blocking timer, with option to repeat):
PHP Code:
/*
# Copyright (C) 2008 David M. Whitney (aka "dwhitney67")
#
# This program is free software: you can redistribute it and/or modify it under 
# the terms of the GNU General Public License as published by the Free Software 
# Foundation, either version 3 of the License, or (at your option) any later 
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT 
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with 
# this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef TIMER_HPP
#define TIMER_HPP

#include <sys/types.h>
#include <sys/select.h>
#include <unistd.h>       // for fork()
#include <cstdlib>        // for exit()
#include <iostream>


template<class T>
class 
Timer
{
  public:
    
enum TimerType
    
{
      
ONE_SHOTREPEATINGCONTINUOUS
    
};

    
enum TimerRunType
    
{
      
BLOCKINGNON_BLOCKING
    
};

    
Timer(int secondsTimerType timerType ONE_SHOTint repeats 1)
    {
      
setupTimer(seconds0timerTyperepeats);
    }

    
Timer(int secondsint microseconds 0TimerType timerType ONE_SHOTint repeats 1)
    {
      
setupTimer(secondsmicrosecondstimerTyperepeats);
    }

    
inline void start(TimerRunType runType BLOCKING)
    {
      
pid_t childPid 0;

      if (
runType == NON_BLOCKING)
      {
        
childPid fork();
      }

      if (
childPid == -1)
      {
        
std::cerr << "failed to start timer process" << std::endl;
      }
      else if (
childPid == 0)
      {
        switch (
type)
        {
          case 
ONE_SHOT:
              
struct timeval tv;
              
tv.tv_sec  seconds;
              
tv.tv_usec microseconds;
              
select(0000, &tv);
              
functor();
              break;

          case 
REPEATING:
          case 
CONTINUOUS:
              
int r repeats;
              while ((
r-- > 0) || (type == CONTINUOUS))
              {
                
struct timeval tv;
                
tv.tv_sec  seconds;
                
tv.tv_usec microseconds;
                
select(0000, &tv);
                
functor();
              }
              break;
        }

        if (
runType == NON_BLOCKING)
        {
          exit(
childPid);
        }
      }
      else
      {
        
// in parent context... just return
      
}
    }

  private:
    
void setupTimer(int secondsint microsecondsTimerType timerTypeint repeats)
    {
      
this->seconds      seconds;
      
this->microseconds microseconds;
      
this->type         timerType;
      
this->repeats      repeats;
    }

    
int       seconds;
    
int       microseconds;
    
TimerType type;
    
int       repeats;
    
T         functor;
};

#endif 
WaitTimer.hpp (a blocking timer):
PHP Code:
/*
# Copyright (C) 2008 David M. Whitney (aka "dwhitney67")
#
# This program is free software: you can redistribute it and/or modify it under 
# the terms of the GNU General Public License as published by the Free Software 
# Foundation, either version 3 of the License, or (at your option) any later 
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT 
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with 
# this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef WAIT_TIMER_HPP
#define WAIT_TIMER_HPP

#include "Timer.hpp"
#include <iostream>


class WaitTimer
{
  private:
    class 
CallbackForTimer
    
{
      public:
        
CallbackForTimer() {}
        
void operator()() { /* nothing to do */ }
    };

    
typedef Timer<CallbackForTimerWaitTimerDef;

  public:
    
WaitTimer(int secondsint milliseconds 0)
        : 
internalTimer(secondsmillisecondsWaitTimerDef::REPEATING1)
    {
    }

    
void start()
    {
      
internalTimer.start(WaitTimerDef::BLOCKING);
    }

  private:
    
WaitTimerDef internalTimer;
};

#endif 
TimerTest.cpp (a test program):
PHP Code:
/*
# Copyright (C) 2008 David M. Whitney (aka "dwhitney67")
#
# This program is free software: you can redistribute it and/or modify it under 
# the terms of the GNU General Public License as published by the Free Software 
# Foundation, either version 3 of the License, or (at your option) any later 
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT 
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with 
# this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "Timer.hpp"
#include "WaitTimer.hpp"
#include <iostream>
#include <string>


class CallbackOne
{
  public:
    
CallbackOne() {}

    
void operator()()
    {
      
std::cout << "CallbackOne operator() has been called" << std::endl;
    }
};


class 
CallbackTwo
{
  public:
    
CallbackTwo() {}

    
int operator()()
    {
      
std::cout << "CallbackTwo operator() has been called" << std::endl;
      return 
10;
    }
};


int main(int argcchar **argv)
{
  
int seconds      1;
  
int microseconds 0;

  
typedef TimerCallbackOne CallbackOneTimer;
  
typedef TimerCallbackTwo CallbackTwoTimer;

  
CallbackOneTimer timerOne(secondsmicrosecondsCallbackOneTimer::REPEATING6);
  
CallbackTwoTimer timerTwo(seconds500         CallbackTwoTimer::REPEATING6);

  
timerOne.start(CallbackOneTimer::NON_BLOCKING);
  
timerTwo.start(CallbackTwoTimer::NON_BLOCKING);

  
// block for 10 seconds so that the callback-timers started above can finish.
  
WaitTimer wt(10);
  
wt.start();

  return 
0;

To compile/link:
Code:
g++ TimerTest.cpp -o timer
Let me know if you have any questions or comments.

dw
 
Old 10-24-2008, 08:58 AM   #9
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by lali.p View Post
@ta0kira But don't you think that such libraries would also be using void* pointer and casting in their implementation ?
If it can be done safely, it can be done without void*. Sure, that's really what's used internally, but there is almost always a way to make things work with templates. I've created some very elaborate function pointer systems without using a single void*. Though not documented, here is my experiment with function pointers from many years ago: http://sourceforge.net/projects/afunct-ta0kira/. No coding standards, I admit, but it's built almost entirely partial specialization. I hope my skills have improved since then
ta0kira
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
a (simple?) function pointer problem mosca Programming 2 08-21-2008 11:02 PM
( C ) How do you declare a function pointer where a parameter is a function pointer? spursrule Programming 5 11-27-2007 07:56 PM
calling a function from a pointer spx2 Programming 3 05-25-2006 04:52 PM
(I know I am inept) what is a pointer function in C ? cigarstub Programming 3 09-27-2005 05:06 PM
void * pointer in function xailer Programming 23 01-16-2004 02:14 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 03:47 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration