How to pass a function ptr with an arg of a specified type OR inheritors of it?

Hello,
I'm facing some issue with the following idea :
I try to use a generic function to register function pointers with a defined type of argument OR ANY inheritors of this type but not other types without using multiple definition of the function with for type (Because I do not want to add another version of this function each time the main class is inherited).

Here is a very simplified example using a "Shape" class with "Circle" and "Square" classes as public inheritors and "Dog" as another class non inheriting from "Shape" defined as follow :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

class Shape{
	public:
	Shape(){};
	~Shape(){};

	virtual void selfIntroduce() const
	{
		std::cout << "I'm a Shape" << std::endl;
	}
};

class Circle: public Shape
{
	public:
	Circle() : m_radius(5) {};
	~Circle(){};

	void selfIntroduce() const
	{
		std::cout << "I'm a Circle" << std::endl;
	}

	private:
	double m_radius;
};

class Square: public Shape
{
	public:
	Square() : m_sideSize(10) {};
	~Square(){};

	void selfIntroduce() const
	{
		std::cout << "I'm a Square" << std::endl;
	}

	private:
	double m_sideSize;
};

class Dog // This is NOT a Shape inheritor
{
	public:
	Dog();
	~Dog();
	
	void selfIntroduce() const
	{
		std::cout << "I'm a Dog" << std::endl;
	}
};


I want to enable the addFuncPtr function to accept "Shape" instances AND inheritors of it (here the "Circle" and "Square" instances). But I do not want addFuncPtr to accept the others classes (here the "Dog" class).

Indeed I could define addFuncPtr with Shape, Circle and Square directly but what I need the most is not having the redefine addFuncPtr each time I create another inheritor of "Shape".

Let's say, someone else create few months later the "Triangle" or "Line" forms inheriting from "Shape", I don't want him to be forced to come into the class where addFuncPtr is defined and having to add another version of the function for each new inheritor type (Triangle, Line...).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

template <typename T>
void addFuncPtr( void(*FuncPtr)(T), T obj )
{
	cout << "addFuncPtr  -->" << &FuncPtr << endl;
	((void(*)(T)) (*FuncPtr))( obj );
}

void testFunc_Form( Shape obj )			//<-- This should be the only one needed for all "Shape" class inheritors 
{
	cout << "testFunc_Form" << endl;
}

void testFunc_Square( Square obj )		//<---- Shouldn't exist as Square is an Inheritor of Shape
{
	cout << "testFunc_Square" << endl;
}

void testFunc_Dog( Dog obj )			//<---- Should exist as Dog is not an inheritor of Shape
{
	cout << "testFunc_Dog" << endl;
}



int main()
{
	Square aSquare;
	Circle aCircle;
	Dog aDog;
	
	addFuncPtr( testFunc_Square, aSquare );		// NO ERROR --> OK.
	//addFuncPtr( testFunc_Form, aSquare );		// ERROR --> NOT OK. this is a Shape inheritor, it should be OK
	
	//addFuncPtr( testFunc_Square, aCircle );	// ERROR --> OK. this is not a Square neither a Square inheritor
	//addFuncPtr( testFunc_Form, aCircle );		// ERROR --> NOT OK. this is a Shape inheritor, it should be OK
	
	addFuncPtr( testFunc_Dog, aDog );		// NO ERROR --> OK.
	//addFuncPtr( testFunc_Form, aDog );		// ERROR --> OK. this is not a Shape neither a Shape inheritor

    return 0;
}


Is there a way to create such a generic function enabling to pass only a specific class AND inheritors of it but not others ?

Thank you very much.

PS : I beg your pardon about my English.

Edit : changed "Form" with "Shape" ... sorry.
Last edited on
There are a few ways to do this. But they're all pretty ugly.

One way would be to derive Dog and Line from a common class where selfIntroduce is virtual:

1
2
3
4
5
6
7
8
9
10
11
12
class Introducer
{
public:
  virtual void selfIntroduce() const = 0;
}

//..
class Form : public Introducer
//...

class Dog : public Introducer
//... 


Another way would be to use boost::bind or a similar functor lib to create a generic function pointer. I don't have an example for this offhand.



Yet another way would be to create your own functor class. I don't recommend this option as it's very messy, but if you want to do it, there are tutorials here:

http://www.newty.de/fpt/functor.html
Hello Disch,
thank you for you reply.

I will study you ideas and see if I can do what I need with you informations.

But while reading once again my own message, I did not found it very clear about what I need so here are some more precisions.

In fact I need this for an event dispatcher.
I what to register for callback function pointers without having to define a register function for each type of Event (new events types can be created by inheriting the main Event class) and indeed I don't want to allow function with argument not being an Event or subclass of Event to be registered...

Consider the following example (with the previous class definition and testFunct_ definition) as a simpler and more direct example of what I try to make.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Approach 1

void testFunc_Form( Shape obj ){}
void testFunc_Square( Square obj ){}
void testFunc_Dog( Dog obj ){}

void addFuncPtr( void(*FuncPtr)( Shape ) ) // Here is my problem (I want to allow only function with Shape argument or inheritors of Shape) !
{
	// some code to register the Function pointer.
}

int main()
{
	// The following is OK as it should.
	addFuncPtr( testFunc_Form );	

	// The following should be OK (because Dog is not an inheritor of Shape) but in fact it is NOT  (that is what I'm trying to change).
	addFuncPtr( testFunc_Square );

	// The following is NOT OK as it should (because Dog is not an inheritor of Shape).
	addFuncPtr( testFunc_Dog);

    return 0;
}


I have also tried with (void*) pointers, but as it now accept the Shape inheritors, it also accept non inheritors... and that's not very secure.

Here is the sample code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Approach 2

void testFunc_Form( Shape obj ){}
void testFunc_Square( Square obj ){}
void testFunc_Dog( Dog obj ){}

void addFuncPtr( void* ) // Here is my problem (I want to allow only function with Shape argument or inheritors of Shape) !
{
	// some code to register the Function pointer.
}

int main()
{
	// The following is OK as it should.
	addFuncPtr( (void*)testFunc_Form );	

	// The following is OK as it should (because Square is an inheritor of Shape).
	addFuncPtr( (void*)testFunc_Square );

	// The following is OK but I wish it's NOT (because Dog is not an inheritor of Shape).
	addFuncPtr( (void*)testFunc_Dog);

    return 0;
}


Approach 1, doesn't fit my need as the testFunct_Square (Square is inheritor of Shape) is not accepted.

Approach 2, works fine but it also doesn't really fit my need as it allow function using non inheritors of "Shape" as argument to be passed.


Hope that, those informations will be more clear than the previous one.
I will do some search using your suggestions.

Thank you

Edit : changed "Form" with "Shape" ... sorry.
Last edited on
I think a compile time check of wether a pair of classes is a superclass-subclass pair could be useful here...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
struct Shape {};
struct Circle : public Shape {};

struct Animal {};
struct Dog : public Animal {};

template <class Super, class Sub>
struct AssertSuperSubClass
{
    Super * sup;
    Sub * sub;

    AssertSuperSubClass():sup(sub){}
};

template <class T>
void AddShapeFuncPtr(void(*FuncPtr)(T))
{
    AssertSuperSubClass<Shape,T>();

    //...
};

template <class T>
void AddAnimalFuncPtr(void(*FuncPtr)(T))
{
    AssertSuperSubClass<Animal,T>();

    //...
};

void testFunc_Shape(Shape obj) {}
void testFunc_Circle(Circle obj) {}
void testFunc_Animal(Animal obj) {}
void testFunc_Dog(Dog obj) {}

int main()
{
    AddShapeFuncPtr(testFunc_Shape); //OK, AS IT SHOULD
    AddShapeFuncPtr(testFunc_Circle); //OK, AS IT SHOULD
    //AddShapeFuncPtr(testFunc_Animal); //PROBLEM, AS IT SHOULD
    //AddShapeFuncPtr(testFunc_Dog); //PROBLEM, AS IT SHOULD

    //AddAnimalFuncPtr(testFunc_Shape); //PROBLEM, AS IT SHOULD
    //AddAnimalFuncPtr(testFunc_Circle); //PROBLEM, AS IT SHOULD
    AddAnimalFuncPtr(testFunc_Animal); //OK, AS IT SHOULD
    AddAnimalFuncPtr(testFunc_Dog); //OK, AS IT SHOULD

    return 0;
}

Though, I have to ask, why do you want to do this? Is this really necessary?
Perhaps you can do what you want to do in a different way,
one that would not make you have to face such a problem.
Last edited on
Hello m4ster r0shi,
your solution does work perfectly. Thank you very much.

To answer your question; As I said in my second message, I need this for an event dispatcher class. The goal is to allow to register function pointers pointing to a function waiting for any kind of Event (Event class or any Event subclass : ClockEvent, InputEvent, AnimationEvent etc.).



void handlerA( ON_INIT, Event evt) {}
void handlerB( ON_UPDATE, ClockEvent evt ) {}
void handlerC( ON_MOUSE_MOVE, InputEvent evt ) {}
etc.

AnyItem myObject; (AnyItem inherit from an EventDispatcher class that give access to addEventListener, dispatchEvent etc.)

myObject.addEventListerner( handlerA );
myObject.addEventListerner( handlerB );
myObject.addEventListerner( handlerC );



My first approach with class template (not shown of this thread) was very clean, but it forced to use only one Event Type per new class... and as it can be useful to enable an item to receive multiple types of Event (not only ClockEvents or not only InputEvents etc...), I tried to find a more flexible way to implement it.

So once again your solution does work very nice.
However, I don't know if this final solution is the most cleanest approach I could use.
naaokth wrote:
As I said in my second message, I need this for an event dispatcher class.

Yes, sorry, I didn't see that.

Hmmm... Just out of curiosity. How does the event listener store the type of the event handler?

And something else. Wouldn't something like this work?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct Event {/*...*/};
struct ClockEvent : public Event {/*...*/};
struct InputEvent : public Event {/*...*/};

void handlerB(Event & evt)
{
    ClockEvent & cevt=dynamic_cast<ClockEvent &>(evt);

    //...
}

void handlerC(Event & evt)
{
    InputEvent & ievt=dynamic_cast<InputEvent &>(evt);

    //...
}

This way, all the event handlers would have the same signature.
Note that I'm not familiar with event driven programming, I'm just throwing an idea.
Last edited on
You don't have to be sorry, you spend your time to help me ^^.

Currently the EventDispatcher class store the listeners in the following container :
std::map< int, std::set< void* >> m_eventsCallbacks;

- the "int" is the hashID (currently using a CRC32 hash) or the Index (could be a simple index) of the EventType (CLOCK_UPDATE, MOUSE_CLICK etc) we want to associate the function pointer with.
- the "void*" is a function pointer to call to dispatch an Event. ( Previously I was using a (void(*)(Event)) instead but as I need to register for different types of pointers I changed to (void*) ... )

Those each hashID can have a set of function pointers to dispatch if any dispatchEvent( hashId ) is called.


I think your proposition is cleaner than mine, but to my point of view it's important to define the handler function directly with the good Event Type family (ie: ClockEvent etc.) to be clear at what the handler is waiting for and needed for.
Last edited on

void (Shape::*fn)()

declares fn to be a pointer to member function of Shape (or derived type) taking no parameters and returning void.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>

struct shape {
    explicit shape( const std::string& color ) : color( color ) {}
    virtual void intro() const { std::cout << color << " shape" << std::endl; }
    std::string color;
};

struct circle : shape {
    circle( const std::string& color, size_t radius ) : shape( color ), radius( radius ) {}
    virtual void intro() const { std::cout << color << " circle with radius " << radius << std::endl; }
    size_t radius;
};

typedef void (shape::*introduce)() const;

void call_it( const introduce& intro, const shape& s ) { (s.*intro)(); }

int main() {
    shape s( "red" );
    circle c( "blue", 42 );

    call_it( &shape::intro, s );
    call_it( &shape::intro, c );
}

Topic archived. No new replies allowed.