How to call a function just using a string?

D

dolphin

Hi All!
I have a question that how to call a function just using a string.
For example
There is a .cpp file named a.cpp.There are some functions::fun1()
fun2() fun3().
I have another fucntion void funcall( char *pch). if I pass a
argument char* p1="fun1" .How do I call the function fun1() using that
string "fun1"that I pass.
 
M

Matthias Buelow

dolphin said:
I have a question that how to call a function just using a string.
For example
There is a .cpp file named a.cpp.There are some functions::fun1()
fun2() fun3().
I have another fucntion void funcall( char *pch). if I pass a
argument char* p1="fun1" .How do I call the function fun1() using that
string "fun1"that I pass.

I'm not aware of any way to do this in portable C++.

Some "solutions":

* Have funcall add some code to a.cpp that allows to select a function
and compile and execute the file,
* dynamically load the file, runtime-binding the desired function(s) and
invoke them,
* make funcall an interface to a C++ interpreter, and run it on a.cpp,
calling the desired function,
* make funcall send a mail to your annoyed cow-orker, instructing him to
edit, compile and run the file so that the desired function will be
executed.
 
M

Matthias Buelow

I said:
Some "solutions":
[...]

I have to add, there's more than just a humouristic aspect to the OP's
question; these kind of questions are perfectly legitimate and fathom
the limits of a programming system. In this example, the border between
data and code in C-style languages is clearly outlined.
 
T

terminator

Hi All!
I have a question that how to call a function just using a string.
For example
There is a .cpp file named a.cpp.There are some functions::fun1()
fun2() fun3().
I have another fucntion void funcall( char *pch). if I pass a
argument char* p1="fun1" .How do I call the function fun1() using that
string "fun1"that I pass.

#include <map>
#include <string>

typedef std::map<std::string,void(*)(void)> FuncMapTypeBase;

struct FuncMapType :
FuncMapTypeBase
{
FuncMapType(){
(*this)["fun1"]=&fun1;
(*this)["fun2"]=&fun2;
(*this)["fun3"]=&fun3;
}
};

const FuncMapType &funxns(){
static FuncMapType funcs;
return funcs;
};

void funcall(const std::string& str){
(*(funcxns()[str]))();
};

regards,
FM
 
A

Abhishek Padmanabh

Hi All!
I have a question that how to call a function just using a string.
For example
There is a .cpp file named a.cpp.There are some functions::fun1()
fun2() fun3().
I have another fucntion void funcall( char *pch). if I pass a
argument char* p1="fun1" .How do I call the function fun1() using that
string "fun1"that I pass.

Does not do exactly what you are asking for but something similar -
dlopen, dlsym and dlclose. This is linux/unix specific. For windows -
you have LoadLibrary and GetProcAddress. For other platforms, you
would need to find alternatives.
 
D

dolphin

Does not do exactly what you are asking for but something similar -
dlopen, dlsym and dlclose. This is linux/unix specific. For windows -
you have LoadLibrary and GetProcAddress. For other platforms, you
would need to find alternatives.

These functions are defined by myself in one .cpp file.Can it be
called by LoadLibrary?
 
T

terminator

These functions are defined by myself in one .cpp file.Can it be
called by LoadLibrary?

It depends on the linkage if you use ordinary (static) linkage the
answer is No.
But if you make some changes to the project specifications or compiler
switches then Yes.

I guess you do not want to use dynamic link libraries;If so please
take a look at my former post.

regards,
FM.
 
M

moxemerald

Dear Terminator,
I find your code to be quite enthralling, however, I do not understand
the bulk of it. =(

Could you comment out your lines so that I understand what is going
on.

Thanks a lot =)
 
K

Kira Yamato

Hi All!
I have a question that how to call a function just using a string.
For example
There is a .cpp file named a.cpp.There are some functions::fun1()
fun2() fun3().
I have another fucntion void funcall( char *pch). if I pass a
argument char* p1="fun1" .How do I call the function fun1() using that
string "fun1"that I pass.

#include <map>
#include <string>

typedef std::map<std::string,void(*)(void)> FuncMapTypeBase;

struct FuncMapType :
FuncMapTypeBase
{
FuncMapType(){
(*this)["fun1"]=&fun1;
(*this)["fun2"]=&fun2;
(*this)["fun3"]=&fun3;
}
};

const FuncMapType &funxns(){
static FuncMapType funcs;

Will this be allowed here? FuncMapType has private constructor.

Otherwise, your code is a nice demonstration of how to do object
aggregation and singleton.
return funcs;
};

void funcall(const std::string& str){
(*(funcxns()[str]))();
};

regards,
FM
 
J

James Kanze

It depends on the linkage if you use ordinary (static) linkage the
answer is No.

I'm not sure I understand. If he links it statically, then he
doesn't need to use LoadLibrary (or dlopen).

I think that the advantage here in using LoadLibrary/dlopen is
that he can add additional functions later, without having to
recompile/relink the main application; in fact, without even
having to stop the main application.

I've done this in one case, albeit with object types derived
from a common base class, not with pure functions. (But of
course, that could be a trivial wrapper for the pure function.)
Basically, the main application contained an std::map<
std::string, Factory* >, where Factory was an abstract base
class with a virtual function which was called to create the
object. The constructor of Factory (called from the derived
class, of course) took a string with the name of the type it
constructs; it knew about the map, and enroled the instance in
the map. This base class and the map was then statically mapped
into the main application. For the derived classes, I
established a naming convention, associating the string with the
name of the corresponding dynamicly loaded file. That file
contained a static instance of the derived factory, so that when
loaded, the constructor would be called, and the factory
register itself with the map. When I wanted an instance of the
class from a string, I looked up the factory in the map; if I
didn't find it, I constructed the file name, tried to load it,
and then tried the map again.

Under Solaris, the only special action necessary was to link
with -ldl. Under Linux, I also needed some special options when
linking the main application, so that symbols in it (e.g. the
constructor of the base class) would be available to the
dynamically linked object. I've not yet had time to port it to
Windows, but from what I understand: 1) I'll need to do
something special to make the constructor for the base class
visible in the DLL's (note that this is the only symbol needed
to establish the link between the objects), and 2) I may have to
move the constructor of the Base class out into a DLL of its own
(presumably with the map, and everything else which uses it),
since I seem to recall having heard that Windows never makes
symbols in the main application available to DLL's (but I really
have no experience here to be sure).

If you really want to get fancy, you can even upgrade functions
dynamically, without stopping the application. Add code in the
destructor of the base class which deenroles the object from the
map, and a (statically linked) command to unload the DLL, and
all you have to do is unload the DLL, replace the file which
contains it with a new one, and the next time someone tries to
use the command, the new one is loaded.
But if you make some changes to the project specifications or
compiler switches then Yes.
I guess you do not want to use dynamic link libraries;If so
please take a look at my former post.

If he's statically linking, the simplest solution is to use a
static table. Something like:

struct MapElement
{
char const* name ;
void (* func)() ;
} ;

MapElement const table[] =
{
{ "do", &do },
{ "re", &re },
{ "mi", &mi },
// ...
} ;

A simple linear search (with std::find_if) will then take care
of the lookup. (I use a similar construct so often that I have
a template for MapElement, which also defined the corresponding
predicate type for std::find_if. Along with the begin and end
functions which return the "iterators" of a C style array, all I
have to write is something like:

typedef StaticMap< void (*)() >
Map ;
Map const myMap[] =
{
{ "do", &do },
{ "re", &re },
{ "mi", &mi },
// ...
} ;

and then:

Map const* elem
= std::find_if( begin( myMap ), end( myMap ),
Map::Matcher( functionName ) ) ;
if ( elem == end( myMap ) ) {
// Error: function not known...
} else {
(*elem->value)() ;
}
 
T

terminator

It depends on the linkage if you use ordinary (static) linkage the
answer is No.

I'm not sure I understand. If he links it statically, then he
doesn't need to use LoadLibrary (or dlopen).

I think that the advantage here in using LoadLibrary/dlopen is
that he can add additional functions later, without having to
recompile/relink the main application; in fact, without even
having to stop the main application.

I've done this in one case, albeit with object types derived
from a common base class, not with pure functions. (But of
course, that could be a trivial wrapper for the pure function.)
Basically, the main application contained an std::map<
std::string, Factory* >, where Factory was an abstract base
class with a virtual function which was called to create the
object. The constructor of Factory (called from the derived
class, of course) took a string with the name of the type it
constructs; it knew about the map, and enroled the instance in
the map. This base class and the map was then statically mapped
into the main application. For the derived classes, I
established a naming convention, associating the string with the
name of the corresponding dynamicly loaded file. That file
contained a static instance of the derived factory, so that when
loaded, the constructor would be called, and the factory
register itself with the map. When I wanted an instance of the
class from a string, I looked up the factory in the map; if I
didn't find it, I constructed the file name, tried to load it,
and then tried the map again.

Under Solaris, the only special action necessary was to link
with -ldl. Under Linux, I also needed some special options when
linking the main application, so that symbols in it (e.g. the
constructor of the base class) would be available to the
dynamically linked object. I've not yet had time to port it to
Windows, but from what I understand: 1) I'll need to do
something special to make the constructor for the base class
visible in the DLL's (note that this is the only symbol needed
to establish the link between the objects), and 2) I may have to
move the constructor of the Base class out into a DLL of its own
(presumably with the map, and everything else which uses it),
since I seem to recall having heard that Windows never makes
symbols in the main application available to DLL's (but I really
have no experience here to be sure).

If you really want to get fancy, you can even upgrade functions
dynamically, without stopping the application. Add code in the
destructor of the base class which deenroles the object from the
map, and a (statically linked) command to unload the DLL, and
all you have to do is unload the DLL, replace the file which
contains it with a new one, and the next time someone tries to
use the command, the new one is loaded.
But if you make some changes to the project specifications or
compiler switches then Yes.
I guess you do not want to use dynamic link libraries;If so
please take a look at my former post.

If he's statically linking, the simplest solution is to use a
static table. Something like:

struct MapElement
{
char const* name ;
void (* func)() ;
} ;

MapElement const table[] =
{
{ "do", &do },
{ "re", &re },
{ "mi", &mi },
// ...
} ;

A simple linear search (with std::find_if) will then take care
of the lookup. (I use a similar construct so often that I have
a template for MapElement, which also defined the corresponding
predicate type for std::find_if. Along with the begin and end
functions which return the "iterators" of a C style array, all I
have to write is something like:

typedef StaticMap< void (*)() >
Map ;
Map const myMap[] =
{
{ "do", &do },
{ "re", &re },
{ "mi", &mi },
// ...
} ;

and then:

Map const* elem
= std::find_if( begin( myMap ), end( myMap ),
Map::Matcher( functionName ) ) ;
if ( elem == end( myMap ) ) {
// Error: function not known...
} else {
(*elem->value)() ;
}

This is of course more efficient but needs more code typing
especifically if readability is trigered.
I just tried to show the posibility via the first and simplest
portable way to write it.

regards,
FM.
 
T

terminator

#include <map>
#include <string>
typedef std::map<std::string,void(*)(void)> FuncMapTypeBase;
struct FuncMapType :
FuncMapTypeBase
{
FuncMapType(){
(*this)["fun1"]=&fun1;
(*this)["fun2"]=&fun2;
(*this)["fun3"]=&fun3;
}
};
const FuncMapType &funxns(){
static FuncMapType funcs;

Will this be allowed here? FuncMapType has private constructor.

Otherwise, your code is a nice demonstration of how to do object
aggregation and singleton.
return funcs;
};
void funcall(const std::string& str){
(*(funcxns()[str]))();
};

had I used the 'class' keyword you would have been ahead by one
point ,But it is a 'struct'( because I am lazy in typing) and has
default public access.

regards,
FM.
 
T

terminator

Dear Terminator,
I find your code to be quite enthralling, however, I do not understand
the bulk of it. =(

Could you comment out your lines so that I understand what is going
on.

We need a global mapper object that maps every desired function to a
string , but global objects couse some troubles in initialization ,so
we need some tricks.
#include <map>
#include <string>

typedef std::map<std::string,void(*)(void)> FuncMapTypeBase;
// define a class in order to initialize a static object.
struct FuncMapType :

/*
inherit from the type that is intended to be used for the static
object:
*/
FuncMapTypeBase
{
/*
define the initializer code for the static object:
*/
FuncMapType(){
(*this)["fun1"]=&fun1;
(*this)["fun2"]=&fun2;
(*this)["fun3"]=&fun3;
}

};

/*
define a static-object-wrapper to make sure the static object is
well constructed before first use:
*/
const FuncMapType &funxns(){
/*
map every function to a string so that you can find it via the
string:
*/
static FuncMapType funcs;
return funcs;

};

//just what the OP wanted:
void funcall(const std::string& str){

// call function pointer 'key'ed by 'str':
(*(funcxns()[str]))();

};

Is it undersandable now?

regards,
FM.
 
K

Kira Yamato

Hi All!
I have a question that how to call a function just using a string.
For example
There is a .cpp file named a.cpp.There are some functions::fun1()
fun2() fun3().
I have another fucntion void funcall( char *pch). if I pass a
argument char* p1="fun1" .How do I call the function fun1() using that
string "fun1"that I pass.
#include <map>
#include <string>
typedef std::map<std::string,void(*)(void)> FuncMapTypeBase;
struct FuncMapType :
FuncMapTypeBase
{
FuncMapType(){
(*this)["fun1"]=&fun1;
(*this)["fun2"]=&fun2;
(*this)["fun3"]=&fun3;
}
};
const FuncMapType &funxns(){
static FuncMapType funcs;

Will this be allowed here? FuncMapType has private constructor.

Otherwise, your code is a nice demonstration of how to do object
aggregation and singleton.
return funcs;
};
void funcall(const std::string& str){
(*(funcxns()[str]))();
};

had I used the 'class' keyword you would have been ahead by one
point ,But it is a 'struct'( because I am lazy in typing) and has
default public access.

Ah. Silly me. Very nice collection of tricks you used in such a small
sample code.
 
J

James Kanze

On Dec 6, 6:59 pm, James Kanze <[email protected]> wrote:

[...]
But if you make some changes to the project specifications
or compiler switches then Yes. I guess you do not want to
use dynamic link libraries;If so please take a look at my
former post.
If he's statically linking, the simplest solution is to use
a static table. Something like:
struct MapElement
{
char const* name ;
void (* func)() ;
} ;
MapElement const table[] =
{
{ "do", &do },
{ "re", &re },
{ "mi", &mi },
// ...
} ;
A simple linear search (with std::find_if) will then take
care of the lookup. (I use a similar construct so often
that I have a template for MapElement, which also defined
the corresponding predicate type for std::find_if. Along
with the begin and end functions which return the
"iterators" of a C style array, all I have to write is
something like:
typedef StaticMap< void (*)() >
Map ;
Map const myMap[] =
{
{ "do", &do },
{ "re", &re },
{ "mi", &mi },
// ...
} ;
and then:
Map const* elem
= std::find_if( begin( myMap ), end( myMap ),
Map::Matcher( functionName ) ) ;
if ( elem == end( myMap ) ) {
// Error: function not known...
} else {
(*elem->value)() ;
}
This is of course more efficient but needs more code typing
especifically if readability is trigered.
I just tried to show the posibility via the first and simplest
portable way to write it.

One of us must have misunderstood something. Your solution
(using std::map) is more efficient---the above uses a linear
search. On the other hand, I find it simpler and more natural
to type the static initializers than the actively type all of
the assignments to the map entries. (You can also initialize
the map from my static table: just add an operator
Map::value_type() const function to MapElement type. But this
does require more typing: you have to declare both the map and
the static table. I also find the table more readable: it
automatically documents the fact that it won't change, and it
doesn't require extra documentation or code to prevent copying,
etc. (or deleting via a pointer to the base).

Also, of course, I have the functions begin() and end(), and the
class template StaticMap, in my toolbox. That's code (including
the code for Map::Matcher) that I don't have to write.

Another difference between using std::map and my suggestion
above: my suggestion uses only static initialization, so is
immune to order of initialization problems. I rather doubt that
this is an issue in the case the OP cited, but in my code for
mapping enum values to and from strings, it could be, and I make
a point of using a static map and std::find_if (by default)
precisely for this reason. (The most frequent use of the
mappings is in tracing, and people do occasionally want to trace
in the constructors of static objects.)

Anyway, there are a number of solutions, with different trade
offs. And none of them are bad---although I suggested an
alternative to yours, I'd certainly accept yours without
hesitation in a code review.
 
T

terminator

[...]




But if you make some changes to the project specifications
or compiler switches then Yes. I guess you do not want to
use dynamic link libraries;If so please take a look at my
former post.
If he's statically linking, the simplest solution is to use
a static table. Something like:
struct MapElement
{
char const* name ;
void (* func)() ;
} ;
MapElement const table[] =
{
{ "do", &do },
{ "re", &re },
{ "mi", &mi },
// ...
} ;
A simple linear search (with std::find_if) will then take
care of the lookup. (I use a similar construct so often
that I have a template for MapElement, which also defined
the corresponding predicate type for std::find_if. Along
with the begin and end functions which return the
"iterators" of a C style array, all I have to write is
something like:
typedef StaticMap< void (*)() >
Map ;
Map const myMap[] =
{
{ "do", &do },
{ "re", &re },
{ "mi", &mi },
// ...
} ;
and then:
Map const* elem
= std::find_if( begin( myMap ), end( myMap ),
Map::Matcher( functionName ) ) ;
if ( elem == end( myMap ) ) {
// Error: function not known...
} else {
(*elem->value)() ;
}
This is of course more efficient but needs more code typing
especifically if readability is trigered.
I just tried to show the posibility via the first and simplest
portable way to write it.

One of us must have misunderstood something. Your solution
(using std::map) is more efficient---the above uses a linear
search. On the other hand, I find it simpler and more natural
to type the static initializers than the actively type all of
the assignments to the map entries. (You can also initialize
the map from my static table: just add an operator
Map::value_type() const function to MapElement type. But this
does require more typing: you have to declare both the map and
the static table. I also find the table more readable: it
automatically documents the fact that it won't change, and it
doesn't require extra documentation or code to prevent copying,
etc. (or deleting via a pointer to the base).

Also, of course, I have the functions begin() and end(), and the
class template StaticMap, in my toolbox. That's code (including
the code for Map::Matcher) that I don't have to write.

Another difference between using std::map and my suggestion
above: my suggestion uses only static initialization, so is
immune to order of initialization problems. I rather doubt that
this is an issue in the case the OP cited, but in my code for
mapping enum values to and from strings, it could be, and I make
a point of using a static map and std::find_if (by default)
precisely for this reason. (The most frequent use of the
mappings is in tracing, and people do occasionally want to trace
in the constructors of static objects.)

I prefer compile time evalutions too ,that is why I liked your
solution.The main issue with yours is the uniqueness of keys which can
be good or bad based on design goals.Mine trigers uniqueness and the
main problem is topological cost of the map(binary up-node-aware-tree
on VC++).
Anyway, there are a number of solutions, with different trade
offs. And none of them are bad---although I suggested an
alternative to yours, I'd certainly accept yours without
hesitation in a code review.

Thanx, at least it means I did not get an F.

best,
FM.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,772
Messages
2,569,593
Members
45,111
Latest member
VetaMcRae
Top