Determine if a function has been defined

Pages: 12
I would like to make a handler for input events, but not be required to define all the functions.

For example, if I had

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void mouseDown(int button,vec2 pos);
void mouseUp(int button,vec2 pos);

static void mouseStateHandle(int button,int state,int x,int y)
{
	switch(state){
		case DOWN:
			mouseDown(button,vec2(x,y));
			break;
		case UP:
			mouseUp(button,vec2(x,y));
			break;
	}
}


(where 'mouseStateHandle' is called whenever a mouse button is pressed or released) and later I had

1
2
3
4
5
6
7
8
void mouseDown(int button,vec2 pos)
{
	switch(button){
		case RIGHT_BUTTON:
			//Woohoo, the right mouse button was pressed!
			break;
	}
}


then the compiler would raise an error because 'mouseUp' was never defined.

Is there some way to do something like
1
2
3
4
5
6
7
8
9
10
11
12
switch(state){
	case DOWN:
		if(mouseDown_is_defined){
			mouseDown(button,vec2(x,y));
			break;
		}
	case UP:
		if(mouseUp_is_defined){
			mouseUp(button,vec2(x,y));
			break;
		}
	}

in the 'mouseStateHandle' function? I don't know enough about C++ to be able to come up with a solution.

Thanks for your consideration :)
You should look up 'function pointers' and 'callbacks' ;)
Thank you, that helped alot! I started coding like mad. The idea of pointers just makes sense to me, even though I have done most of my coding in Lua, a type-less pointer-less language.

Now the issue is in assigning the function to the function pointer.

New code:

ControlEvents.cpp
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
void mouseDownDefault(int button,vec2 pos)
{
	//Place holder
}
void mouseUpDefault(int button,vec2 pos)
{
	//Place holder
}


void (*mouseDownEvent)(int,vec2)=mouseDownDefault;
void (*mouseUpEvent)(int,vec2)=mouseUpDefault;

static void mouseStateHandle(int button,int state,int x,int y)
{
	switch(state){
		case DOWN:
			if(*mouseDownEvent!=&mouseDownDefault)
				mouseDownEvent(button,vec2(x,y));
			break;
		case UP:
			if(*mouseUpEvent!=&mouseUpDefault)
				mouseUpEvent(button,vec2(x,y));
			break;
	}
}

void ControlEventsInit()
{
	//Hook up mouseStateHandler to the actual callback
}


Controls.cpp
1
2
3
4
5
6
7
8
9
10
void mouseDown(int button,vec2 pos)
{
	switch(button){
		case RIGHT_BUTTON:
			cout<<"Woohoo, the right mouse button was pressed!"<<endl;
			break;
	}
}
mouseDownEvent=&mouseDown;
//The compiler doesn't like this, it tells me 'mouseDownEvent' does not name a type, but it doesn't need one because it was already defined. 


main.cpp
1
2
3
4
5
6
7
#include "ControlEvents.cpp"
#include "Controls.cpp"

int main(int argc, char** argv)
{
	ControlEventsInit();
}


The files obviously contain more than that, but I feel that this is the relevant information. Tell me if more information is required to solve this problem.
Last edited on
The compiler doesn't like this, it tells me 'mouseDownEvent' does not name a type, but it doesn't need one because it was already defined.
mouseDownEvent is a global variable like any other. That means you need to declare it (in a header with extern) so that the compiler knows the type.
Ideally, the functions would be passed to ControlEventsInit, rather than being transmitted by global variables. (I think that is what you intended ControlEventsInit to do, anyway)
Thanks for the suggestions, but when I changed it to

ControlEvents.h
1
2
3
4
5
6
7
extern void (*updateEvent)(double);
extern void (*mouseEnterEvent)();
extern void (*mouseLeaveEvent)();
extern void (*mouseMovedEvent)(vec2);
extern void (*mouseDownEvent)(int,vec2);
extern void (*mouseUpEvent)(int,vec2);
extern void (*keyDownEvent)(unsigned char);


ControlEvents.cpp
1
2
3
4
5
6
7
updateEvent=updateDefault;
mouseEnterEvent=mouseEnterDefault;
mouseLeaveEvent=mouseLeaveDefault;
mouseMovedEvent=mouseMovedDefault;
mouseDownEvent=mouseDownDefault;
mouseUpEvent=mouseUpDefault;
keyDownEvent=keyDownDefault;


main.cpp
1
2
3
#include "controlEvents.h"
#include "ControlEvents.cpp"
#include "Controls.cpp" 


The compiler still says the same error, but now in ControlEvents.cpp:

ControlEvents.cpp:line:col: error: 'WhatevaEvent' does not name a type

for all the events.
this just declares the global variable. As LB said you might not even want them.

Use typedef for the type.

1
2
3
4
5
6
typedef void (*updateEvent_func)(double);

void ControlEventsInit(updateEvent_func f)
{
  f(1.0);
}


[EDIT]
you may want to take a look at the boost functions:

http://www.boost.org/doc/libs/1_53_0/doc/html/function.html
Last edited on
Those lines you added in ControlEvents.cpp are statements, not definitions.

1
2
3
extern int example; //declaration (you have this)
int example = 7; //definition (this is what you *should* have)
example = 9; //statement (this is wgat you currently have) 


Again, though, you really should not be using global variables. Instead the handlers should be set via the user calling a function to define them, such as passing them to your ControlEventsInit function, and using default handlers for when they pass null.
Last edited on
I'd really like to go this way, since it would make future projects for me simpler to get set up. I am willing to change if it proves to be too difficult though.

this just declares the global variable.

How would I allow the variable to vary? It seems ridiculous to me that a variable can't vary! When I gave the compiler what it is asking for (a type) with typedefs, it told me that the variable was being redefined. I thought "I know, I want that!"

This is the contents of the ControlEventsInit function, it never touches the globals I'm making for my convenience:

1
2
3
4
5
6
7
8
void ControlEventsInit()
{
	glutEntryFunc(mouseEntryHandle);
	glutMouseFunc(mouseStateHandle);
	glutKeyboardFunc(keyboardHandle);
	glutMotionFunc(mouseMotionHandle);
	glutPassiveMotionFunc(mouseMotionHandle);
}



1
2
3
extern int example; //declaration (you have this)
int example = 7; //definition (this is what you *should* have)
example = 9; //statement (this is what you currently have)  



The middle example is what I used to have. Function pointers seem to behave different than any other type of variable, so I'm not sure that that summarizes my situation properly.

I can't pass them as arguments to my initiation function, because it has absolutely nothing to do with them, so I've come to another point where progress stops. :/
Last edited on
You're misunderstanding every one of our posts.

krakow10 wrote:
I'd really like to go this way, since it would make future projects for me simpler to get set up. I am willing to change if it proves to be too difficult though.
Nothing I am saying is forcing you to do things in a harder way. The way I recommend is more modular and much easier in the long run.

krakow10 wrote:
How would I allow the variable to vary? It seems ridiculous to me that a variable can't vary! When I gave the compiler what it is asking for (a type) with typedefs, it told me that the variable was being redefined. I thought "I know, I want that!"
You've misunderstood:
1
2
3
4
5
6
7
8
int x = 7; //global variable

x = 8; //not allowed outside a function

int main()
{
    x = 8; //this IS allowed, it is in a function
}
Again, though, this is why you should not be using global variables.

I'll prepare an example if you're still confused.
I have never been told that, interesting. It fixed my problem yay! However, I have to do odd things to make the compiler happy:


1
2
3
4
5
6
7
int whaddaphuk()
{
	keyDownEvent=keyDown;
	mouseDownEvent=mouseDown;
	return 0;
}
int garbage=whaddaphuk();
I see, you can't do anything outside of functions. Restricting, but good to know!

I changed my odd code to this:
Control.cpp
1
2
3
4
5
void Connect()
{
	keyDownEvent=keyDown;
	mouseDownEvent=mouseDown;
}


main.cpp
1
2
3
4
5
int main(int argc, char** argv)
{
	Connect();
	ControlEventsInit();
}


and everything works. Thanks for the help guys!
I see, you can't do anything outside of functions. Restricting, but good to know!

It's not "restricting" - it's the only thing that makes sense. When exactly would you expect a line of code that's not in a function to be executed?
@MikeyBoy in many other languages, there is no such thing as a main function, code is just executed in the order it is written or imported. It's all the craze these days, but personally I think it encourages looser designs.
Yes, there are scripted languages that work like that. I've been doing some Python work lately, and it works just like that - a script runs from top to bottom, unless the control flow is directed by, e.g., a function all.

But (and I know you know this - this is for the OP's benefit) - C++ doesn't work like that. It operates under different expectations and a different context. Hence my question.

The correct answer, even if it were allowed, would be: you wouldn't know when it was executed. This is one of the many problems with using global variables - you can't ever know in which order those objects will be instantiated, and the problem would be even worse if more code execution was allowed outside functions/methods.
Here's another thing: main isn't a function. It looks like one, but it's not, which is why the return statement is optional and you're not supposed to call main it template it or overload it or take its address ...etc.
It's basically the equivalent of executing code in the global scope in other languages. The global scope isn't a function. It looks like one, but it's not, which is why the exit statement is optional and you can't call it or genericize it or overload it or pass it as a functor ...etc.
In many other languages, there is no such thing as a main function...

I made an entire paintball game in ROBLOX in Lua, and in my 7000 lines of code, I strongly relied on this feature.
http://www.roblox.com/--place?id=97680268

For example, I would use for loops to initialize variables in the global scope (which is actually a function, which you can obtain within your code, but that's besides the point). In this Lua code (-- denotes a comment):

1
2
3
4
5
6
7
local nt=5--number of value types (numtypes)
local timenames={" second"," minute"," hour"," day"," year"}
local timemods={1,60,60,24,365}--how many of the previous value = 1 of this value
local timemults={1}
for i=2,nt do
	timemults[i]=timemults[i-1]*timemods[i]
end

the loop at the end is a big loud "I'm lazy". Oh, and by the way tables start at index 1 in Lua, because it's easier to learn. I had no trouble accepting and using arrays in C++ starting at 0. However, perhaps the best analogy of Lua's tables in C++ is the vector? Tables are really something else.

When exactly would you expect a line of code that's not in a function to be executed?


Exactly in order from top to bottom ;)


From my point of view, functions were used as a tool to organize repeated code, or to ease the amount of nesting in the code.
Exactly in order from top to bottom ;)

Which works fine when you have a single file, i.e. for the most elementary of tutorial exercises. But in the real world...

I have a project with 3 files, A.cpp, B.cpp, and C.cpp, which are linked together to create an application. In which order would this hypothetical global-scope code in these 3 files execute?

Oh, wait, I've already answered it:

The correct answer, even if it were allowed, would be: you wouldn't know when it was executed. This is one of the many problems with using global variables - you can't ever know in which order those objects will be instantiated, and the problem would be even worse if more code execution was allowed outside functions/methods.


In other words - the creation of stuff in global scope happens in a jumble. It get done in whatever order the compiler - or, rather, the linker - chooses to have it done. This is already problematic when the only execution that happens in the global scope is the instantiation of global objects; how much worse would it be if we were executing more code?

In Python, it's easy, because you don't link files, you "import" them, so when the script interpreter reaches that import line, it begins execution - from top to bottom - of the imported file. It's analogous to the way the C++ preprocessor resolves a #include statement during compilation. But that's compilation - NOT runtime. There is no runtime analogy to Python's "import" statement.

I'm sure you, krakow10, know this already - but there will be people reading this forum who don't.

The C++ standard defines no order for the initialization of global variables across multiple compilation units, therefore you should consider the order of execution of all global initializes to be undefined, even if in the same file (what if you later move one and forget about the required order?)
Last edited on
Yes, exactly what I've been saying :)
Pages: 12