Void* cast to STD::string, output wrong...

So hopefully this is a simple question...

I have (assume all the right H files are loaded):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
typedef void(*function)(void*);
std::map<std::string, function> funcmap;

void doCreate(void *_args){
    //intended to be passed a string, testing using Void* and string casting.
	std::string strVal = *(std::string *)_args; //if breakpointed, strVal == Str1.
	
	if (strVal == "Str1") //as strVal == Str1 this is true.
		fprintf(stdout, "Str1 is set but it = %s\n", strVal); //output is: "Str1 is set but it = <unicode characters>"

	fprintf(stdout, "value  = %s\n", strVal); //output is the same as above: "value = <unicode characters>"
}

void functionRun(std::string s){
	std::string strings;
	strings = "Str1"; 
	(*funcmap.at(s))(&strings);
}

void main(){
    funcmap["onCreate"] = doCreate;
    functionRun("onCreate");
}


I'm trying to learn the whole void* recasting trick to do pointered functions for an event management system... in this case the variables look right in the debug window when a breakpoint is fired. however fprintf is outputting gibberish as though i'm outputing a memory location, however i dont think this should be the case...

Can someone give me a pointer (no pun intended) in the right direction?
Last edited on
If you're explicitly casting to std::string, why not just pass std::string?
If your event management system requires the use of a void pointer via C++, I'd wager you're doing it wrong. You wouldn't do this, even in ISO C.

But to answer your question... is not possible. The above code doesn't compile: http://ideone.com/DtCXVn

To fix this, you would have to do two things:

1) main() always returns int!
2) It's telling you that you cannot pass the type std::string to fprintf. You're also asking for %s which is for a C string pointer or null-terminated char*.

Here's a working version: http://ideone.com/DtCXVn

Do you mind me asking what compiler / tutorial you're using?
Last edited on
Functions of the *printf() family are incompatible with std::string. Use std::string::c_str(). For example, strVal.c_str().

By the way, you could avoid a string copy:
 
std::string &strVal = *(std::string *)_args;
Last edited on
So the code that i've supplied is a snippit of the various 'important' functions and i hand wrote the main... so its probably wrong...

agreed it should be an int...

if you fix the main, and add in includes for <string> and <map>, it should compile... however, i think you're right about the null-terminated char*... when the same output is run prior to entering the pointered function, it too is outputting the same values.

As far as compiler / tutorial, i'm hacking the code myself... its been very hard to find any meaningful and useful tutorials on function pointers, particularly with arguments that aren't simply "You declare it this way", "Then you call it this way".

The fix was simple, and to your point 2, it was a case of simply adding .c_str() to the string call... thanks.

To expand the question, how would you do a variable event system? for example, on an action "OnCollide" do a variable outcome for the activity... one object might be "destroy" another "create" and another "nothing"...
Last edited on
That's the purpose of virtual interfaces from what I perceive of what you're saying.
So abstract classes and virtual interfaces might be options... but the issue with abstract classes is that you don't get to redefine behavior on the fly.

Its very possible that i'm over complicating the issue, however, the way that i was thinking it through was that when i want to change behavior on an object that i could change the function pointer associated to the mapped behavior.

for example:
funcmap["onCollision"] = doDestroy
funcmap["onCreate"] = doCreate
and if i wanted to do so:
funcmap["onVictory"] = doDestroy
or conversely
funcmap["onCreate"] = doDestroy

then being able to call the functions using a string in functionRun(string);
funcmap.at(string)(<arguments>);

this allows the individual objects to simply shortcut a very large set of case statements, and execute functions based on the calling 'name'.

the comparison is:
switch (action):
case ("onCollision"){
doDestroy(args);
break;
}
case ("onCreate"){
doCreate(args);
break;
}
....

in my head, if there are 'templatised' functions, referencing them in this way makes a great deal of sense, and possibly even faster...
Last edited on
You'll almost never need that kind of power. Something like this is much more common:
1
2
3
4
5
6
7
8
9
10
class GenericParameter{
public:
    virtual ~GenericParameter(){}
    virtual bool to_int(int &) = 0;
    virtual bool to_double(double &) = 0;
    virtual bool to_string(std::string &) = 0;
    //etc. Using exceptions is also a possibility.
};

void (*generic_function)(const std::vector<GenericParameter *> &);
Topic archived. No new replies allowed.