I want to declare a map of function pointers where an enum is the key value,
and various function pointers are the mapped value. How do you do this?
Printable View
I want to declare a map of function pointers where an enum is the key value,
and various function pointers are the mapped value. How do you do this?
Change as desired.Code:std::map<my_enum, void (*)(int)> my_map;
Then must all my functions return void and take an integer as their parameter? What if I want all different kinds of funcitons (that return differently, and take different params)?
Then you would have a problem...
I'm not sure of the solution. I'm sure boost has some interesting containers to store stuff, though.
It's much easier with typedefs.
Also I would prefer member function pointers instead of C function pointers.
Code:class Object
{
typedef void (Object::*FUNCPTR)(const char *pSomething);
typedef std::map<std::string, FUNCPTR> FuncMap;
FuncMap m_MemberFunctionMap;
};
But then how would you know how each item in the map is to be called and where the result goes?
There is a way to do this using a union. MFC code utilizes this for their message map system. I'll show you what I came up with to remedy a similar problem.
Keep in mind this is just an example and I pulled a lot of it from MFC's method of handling message maps.
Be prepared because this is ugly.
I've since moved on to a map of member function pointers.
Code:#include <vector>
#include <utility>
#include "CBaseObject.h"
/////////////////////////////////
//Script message map structures//
/////////////////////////////////
//Forward delcaration of CBaseObject;
class CBaseObject;
//SCRIPT_MSG typedef
typedef void (CBaseObject::*SCRIPT_MSG)(void);
//SCRIPT_MSGMAP_ENTRY
struct SCRIPT_MSGMAP_ENTRY
{
UINT nCommandID;
UINT nFuncSig;
SCRIPT_MSG pfn;
//SCRIPT_MSGMAP_ENTRY(UINT nCommandID,UINT nFuncSig,SCRIPT_MSG pfn):
//nCommandID(nCommandID),nFuncSig(nFuncSig),pfn(pfn) { }
};
//SCRIPT_MSGMAP
struct SCRIPT_MSGMAP
{
const SCRIPT_MSGMAP *pBaseMap;
std::vector<SCRIPT_MSGMAP_ENTRY *> vEntries;
};
//Function type signatures - to determine params
enum SFuncSigs
{
SFSig_Param0_n =0,
SFSig_Param1_n, //int fxn(DWORD)
SFSig_Param2_n, //int fxn(DWORD,DWORD)
SFSig_Param3_n //int fxn(DWORD,DWORD,DWORD)
};
//Actual script function declarations
union ScriptMsgMapFuncs
{
SCRIPT_MSG pfn;
UINT (CBaseObject::*pfnParam1_n)(void);
UINT (CBaseObject::*pfnParam2_n)(DWORD);
UINT (CBaseObject::*pfnParam3_n)(DWORD,DWORD);
};
//Declaration of the script message map
//Adds a vector, parent object, and 3 new functions to CBaseObject
#define DECLARE_SCRIPT_MSGMAP() \
protected: \
static std::vector<SCRIPT_MSGMAP_ENTRY *> m_vEntries; \
static CBaseObject *m_pParent; \
public: \
static const void SetupMessageMap(void); \
static const void AddHandler(UINT nCommandID,UINT nFuncSig,SCRIPT_MSG memberFxn); \
static const void SetParent(CBaseObject *pParent);
//Must precede the start of every script message map
#define BEGIN_SCRIPT_MSGMAP(theClass,baseClass) \
std::vector<SCRIPT_MSGMAP_ENTRY *> theClass::m_vEntries; \
CBaseObject *theClass::m_pParent=baseClass; \
const void theClass::AddHandler(UINT nCommandID,UINT nFuncSig,SCRIPT_MSG memberFxn) \
{ \
SCRIPT_MSGMAP_ENTRY *pEntry=new SCRIPT_MSGMAP_ENTRY; \
pEntry->nCommandID=nCommandID; \
pEntry->nFuncSig=nFuncSig; \
pEntry->pfn=memberFxn; \
m_vEntries.push_back(pEntry); \
} \
const void theClass::SetupMessageMap(void) {
//Script handler type 1 - unary script function
#define ON_SCRIPT_CMD1(id,memberFxn) \
AddHandler(id,SFSig_Param1_n,(SCRIPT_MSG)memberFxn);
//Script handler type 2 - binary script function
#define ON_SCRIPT_CMD2(id,memberFxn) \
AddHandler(id,SFSig_Param2_n,(SCRIPT_MSG)memberFxn);
//Script handler type 3 - trinary script function
#define ON_SCRIPT_CMD3(id,memberFxn) \
AddHandler(id,SFSig_Param3_n,(SCRIPT_MSG)memberFxn);
//Ends a script message map
#define END_SCRIPT_MSGMAP }
Thank You all.
So I'm led to beleive using a map of function pointers is only useful if the functions themselves are relatively similar (and neccessarily similar in return type, and paramter list)?
Well, apparently so. What are you trying to do?
Well I was exploring the idea in my other thread about user access and the functions they can perform. I was thinking of the following abstraction:
but I don't think now that mapping function pointers is a good idea at least for my problem.Code:User makes request to access a function. If a user's key matches the function's key,
they're allowed to carry out the action. The request is processed by a central mechanism (Access Control in my example here):
Users --- Make Request ---> Access Control --- Look up function/key pair ---> Function
With what parameters though? How will the user specify the parameters if he doesn't know the function?
You cad have a void* (fun)(void *) function and pass a struct, which will hold the parameters. And then cast it. As you do with POSIX Threads.
What you can do is this (if you want to work that way).
The User selects the type of functions. You have a std::map with keys and function pointers, that would be "vector<void*> (*fun)(vector<void*>&)"
The users selects the parameters. The parameters are inserted to a vector<void *>. You use the key to find the appropriate function from your map. You call the function. Its function will now how to cast the parameters.
Or, better, since the above might be considered unsafe/evil because of the casting, you have a "void* (*fun)(void*)", exactly like PThreads. You have a second std::map in which you have the same keys and void*. Each pointer will point at a specific class, which will have parameters stored in it. So the user will pass the parameters and the function will be called correctly. Like (w/o the second map):
or just do this if you have a way to take parameters with another way and putting them in mapPar(using two maps as I described above)Code:class par1
{
int a;
in b;
};
class par2
{
char a;
char b;
char c;
};
...
cout << "Select key"
cin >> key;
...
cout << "Select parameters";
void* par = insertCorrectParameters(key);
map[key](par);
...
void* insertCorrectParameters(Keys key)
{
switch(key)
{
case 1:
par1 par;
//fill class;
return (void*)par;
case 2:
par2 par;
....
}
}
...
...
void* fun1(void* par)
{
par1 p = (par1*)par;
...
}
void* fun2(void* par)
{
par2 p = (par2*)par;
...
}
and you 're done (I hope)Code:mapFun[key](mapPar[key]);
At this point, you should just turn your function pointers into function objects, and thus be rid (or at least hide) the use of void* entirely.Quote:
Originally Posted by C_ntua
Stop right there! This is C++, not C!
Even more horrible -_-Quote:
You have a std::map with keys and function pointers, that would be "vector<void*> (*fun)(vector<void*>&)"
The users selects the parameters. The parameters are inserted to a vector<void *>. You use the key to find the appropriate function from your map. You call the function. Its function will now how to cast the parameters.
Or, better, since the above might be considered unsafe/evil because of the casting, youHorrors of horrors!Quote:
have a "void* (*fun)(void*)", exactly like PThreads. You have a second std::map in which you have the same keys and void*. Each pointer will point at a specific class, which will have parameters stored in it. So the user will pass the parameters and the function will be called correctly. Like (w/o the second map):
Stop passing void* - it's evil, it's bad and it's not C++!
This kindof sounds like the job boost::bind. You create a functor, in which you might store a function along with its parameters (ie, bind them). Then you pass them along to the function which checks the permission and executes it if it's A-OK.
C_ntua, I seriously suggest you start boosting up your knowledge of templates and designs, like functors.
Passing void* is the old C way, which you should avoid like the plague in today's C++ - it offers so much more better designs!
functors would be one solution.
The other solution, more C-like but still workable, assuming that the number of keys and functions are equal and relatively small would be to use a fixed class/struct that holds pairs of keys and functions, where each function is declared correctly with actual return value and parameters.
--
Mats
Wasn't aware of function objects, so looked 'em up a bit. Just to see if I understand the concept of them. Could you do something like:
So, doFun will practically do f1() which will do sum += a+b? Or will my code, most likely, do nothing :)?Code:class fun1
{
int a, b;
int sum;
public:
void setVal(int c, int d){a = c; b = d;}
int getVal(){return sum;}
void operator() () {sum += a + b;}
fun1(){sum = 0;}
};
//general function
template <class Fun>
void doFun(Fun fun)
{
fun();
}
//in main
fun1 f1;
f1.getVal(2, 3);
doFun<fun1>(f1); //or doFun(f1) ??
int sum = f1.getVal();
doFun(f1) works just fine. You have a typo in the first getVal should be setVal, but otherwise, yes, it should work.
Just a small clarification: how come you don't use the <> since you have a template function?
<> is only required for classes, or when the compiler cannot deduce the type of the template parameter. In this case, since you pass an object of a certain type, the compiler can easily deduce the actual type of the template parameter.
If I knew more about templates, I'd probably know the answer to the question I'm about to ask, but can templates take function pointers at their type? And if so, could the magic of templates/specialization be used to allow function pointers of any return type/parameter list?
I know what I've been trying to do hasn't been exactly clear. Here's a small example I wrote up. Basically I'm looking for a more elegant way to do what I've got here:
Basically the whole checkUserAccess mechanism just seems broke in design and implementation.Code:#include <iostream>
#include <map>
typedef unsigned char uchar;
enum ACCESS_TYPE{
ACCESS_1,
ACCESS_2
};
void fxn1(){
std::cout << "Function 1.\n";
}
int fxn2( int n ){
std::cout << "Function 2.\n";
return n;
}
class User{
public:
User( uchar key ) : key( key ) {};
const uchar& getUserKey() const { return key; }
void setUserKey( uchar newKey ){ key = newKey; }
private:
uchar key;
};
void checkUserAccess( std::map<ACCESS_TYPE, uchar>& fxnMap, ACCESS_TYPE accessType, User& user ){
std::map<ACCESS_TYPE, uchar>::iterator it = fxnMap.find( accessType );
switch( accessType ){
case( ACCESS_1 ):{
if( ( it->second & user.getUserKey() ) == it->second ){
std::cout << "User has access.\n";
fxn1();
}
else
std::cout << "User does not have access.\n";
break;
}
case( ACCESS_2 ):{
if( ( it->second & user.getUserKey() ) == it->second ){
std::cout << "User has access.\n";
int x = fxn2( 5 );
}
else
std::cout << "User does not have access.\n";
break;
}
}
}
int main(){
User John( 0x0B );
std::map<ACCESS_TYPE, uchar> fxnMap;
fxnMap.insert( std::pair<ACCESS_TYPE, uchar>( ACCESS_1, 0x04 ) );
fxnMap.insert( std::pair<ACCESS_TYPE, uchar>( ACCESS_2, 0x08 ) );
checkUserAccess( fxnMap, ACCESS_1, John );
checkUserAccess( fxnMap, ACCESS_2, John );
return 0;
}
As you are using bit fiddling to do the work anyway, this is a much simpler form:
Code:#include <iostream>
#include <map>
typedef unsigned char uchar;
enum ACCESS_TYPE{
ACCESS_1 = 0x04,
ACCESS_2 = 0x08
};
void fxn1(){
std::cout << "Function 1.\n";
}
int fxn2( int n ){
std::cout << "Function 2.\n";
return n;
}
class User{
public:
User( uchar key ) : key( key ) {};
const uchar& getUserKey() const { return key; }
void setUserKey( uchar newKey ){ key = newKey; }
private:
uchar key;
};
void checkUserAccess(ACCESS_TYPE accessType, User& user ){
switch( accessType ){
case( ACCESS_1 ):{
if( ( ACCESS_1 & user.getUserKey() ) == ACCESS_1 ){
std::cout << "User has access.\n";
fxn1();
}
else
std::cout << "User does not have access.\n";
break;
}
case( ACCESS_2 ):{
if( ( ACCESS_2 & user.getUserKey() ) == ACCESS_2 ){
std::cout << "User has access.\n";
int x = fxn2( 5 );
}
else
std::cout << "User does not have access.\n";
break;
}
}
}
int main(){
User John( 0x0B );
checkUserAccess( ACCESS_1, John );
checkUserAccess( ACCESS_2, John );
return 0;
}
Ahhh, that's what happens when I NEVER use enums! My biggest weakness: my C++ repertoire! That's really good actually, thanx phanomotap!
In the future, you might try to do a better job of telling the people trying to help you what you actually want to do. The people who've posted so far definitely would have helped you with that a long time ago.
Soma
Just a small note. Even though you don't seem to need something like a function object or another implementation noted above, if you have a lot of access type it would be a good idea to use them. Instead of writing fxn1() or int x = fxn2(5) in your example you could just write something general, like doFun(fxn1), doFun(fxn2).
That will have the advantage that if you change fxn1, or fxn2 you will just change the class and won't risk making mistakes from rewriting things in your checkUsersAccess functions. In a way you will have a more clear code.
Well, what phanomotap posted helps me only somewhat. It's certainly not the end-all answer to my problem. Like, where do the parameters come from if different functions require different param lists? That's a problem I still need to tackle.
In this app, I can't make any assumptions like how many different functions there might be, and especially what kind of param lists of those different functions have.
I'm still seeking a more general solution to this problem and I will have to explore many of the ideas others have posted here. Right now, Bubba's suggestion of member function pointers seems to be one good option, and I'll explore that and others more in depth.
Forgive me if I didn't clearly define the problem, but mine is a rather complex one, and at this point I'm only coming up with "It could be done this way" solutions and not "It should be done this way" solutions. When I find that, my job will be done.
In addition, other programmers are laying the infrastructure for this app (developing only the absolute minimum required by Jan 15), and I don't know if any model/solution I come up with will actually fit with what they have (this is the unfortunate process of government & government-contract software projects).
*shrug*
I looked up this up for you because I was curious if I still had it.
Creating and parsing some generic representation of both the parameter lists and the return type in a manager of some sort is the only way you will be able to do what you may want.
However, from the ambiguous way you are describing your goal it also may be as simple as mapping a 'void (*)()' to any other type by using a simple polymorphic function object. (This has already been suggested.)
The point is, what do you really want?
"Like, where do the parameters come from if different functions require different param lists?", for example, isn't helpful. Where do you want them to come from? At what point will you have enough information to know what arguments should be passed? Are the arguments the same for any given association? Or are they always different?
Soma
Code:#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <map>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
struct vafb
{
struct association
{
static const unsigned long vfv = 0;
static const unsigned long sfv = 1;
static const unsigned long sfs = 2;
static const unsigned long sfss = 3;
static const unsigned long sfm = 4;
};
vafb(){}
virtual ~vafb(){}
virtual void vfv(){throw std::runtime_error("Invalid Function!");}
virtual std::string sfv(){throw std::runtime_error("Invalid Function!");}
virtual std::string sfs(const std::string &){throw std::runtime_error("Invalid Function!");}
virtual std::string sfss(const std::string &, const std::string &){throw std::runtime_error("Invalid Function!");}
virtual std::string sfm(const std::vector<std::string> &){throw std::runtime_error("Invalid Function!");}
virtual unsigned long vafb_type() = 0;
};
template <typename return_t, typename parameter_1_t, typename parameter_2_t> struct auto_vafb: public vafb
{
typedef return_t (*function_type)(parameter_1_t, parameter_2_t);
auto_vafb(function_type function): function_m(function)
{
}
virtual std::string sfss(const std::string & parameter_1, const std::string & parameter_2)
{
std::istringstream parameter_1_stream(parameter_1);
std::istringstream parameter_2_stream(parameter_2);
parameter_1_t modified_parameter_1;
parameter_2_t modified_parameter_2;
std::ostringstream return_value_stream;
parameter_1_stream >> modified_parameter_1;
parameter_2_stream >> modified_parameter_2;
return_value_stream << function_m(modified_parameter_1, modified_parameter_2);
return(return_value_stream.str());
}
virtual unsigned long vafb_type()
{
return(vafb::association::sfss);
}
function_type function_m;
};
template <typename return_t, typename parameter_1_t> struct auto_vafb<return_t, std::vector<parameter_1_t>, void>: public vafb
{
typedef return_t (*function_type)(const std::vector<parameter_1_t> &);
auto_vafb(function_type function): function_m(function)
{
}
virtual std::string sfm(const std::vector<std::string> & parameter_1)
{
const std::vector<std::string>::size_type size(parameter_1.size());
std::vector<parameter_1_t> values(size);
for(std::vector<std::string>::size_type cursor(0); cursor < size; ++cursor)
{
std::istringstream parameter_stream(parameter_1[cursor]);
parameter_1_t modified_parameter;
parameter_stream >> modified_parameter;
values[cursor] = modified_parameter;
}
std::ostringstream return_value_stream;
return_value_stream << function_m(values);
return(return_value_stream.str());
}
virtual unsigned long vafb_type()
{
return(vafb::association::sfm);
}
function_type function_m;
};
template <typename return_t, typename parameter_1_t> struct auto_vafb<return_t, parameter_1_t, void>: public vafb
{
typedef return_t (*function_type)(parameter_1_t);
auto_vafb(function_type function): function_m(function)
{
}
virtual std::string sfs(const std::string & parameter_1)
{
std::istringstream parameter_1_stream(parameter_1);
parameter_1_t modified_parameter_1;
std::ostringstream return_value_stream;
parameter_1_stream >> modified_parameter_1;
return_value_stream << function_m(modified_parameter_1);
return(return_value_stream.str());
}
virtual unsigned long vafb_type()
{
return(vafb::association::sfs);
}
function_type function_m;
};
template <typename return_t> struct auto_vafb<return_t, void, void>: public vafb
{
typedef return_t (*function_type)();
auto_vafb(function_type function): function_m(function)
{
}
virtual std::string sfv()
{
std::ostringstream return_value_stream;
return_value_stream << function_m();
return(return_value_stream.str());
}
virtual unsigned long vafb_type()
{
return(vafb::association::sfv);
}
function_type function_m;
};
template <> struct auto_vafb<void, void, void>: public vafb
{
typedef void (*function_type)();
auto_vafb(function_type function): function_m(function)
{
}
virtual void vfv()
{
function_m();
}
virtual unsigned long vafb_type()
{
return(vafb::association::vfv);
}
function_type function_m;
};
template <typename return_t, typename parameter_1_t, typename parameter_2_t> vafb * craft_vafb(return_t (*function)(parameter_1_t, parameter_2_t))
{
return(new auto_vafb<return_t, parameter_1_t, parameter_2_t>(function));
};
template <typename return_t, typename parameter_1_t> vafb * craft_vafb(return_t (*function)(const std::vector<parameter_1_t> &))
{
return(new auto_vafb<return_t, std::vector<parameter_1_t>, void>(function));
};
template <typename return_t, typename parameter_1_t> vafb * craft_vafb(return_t (*function)(parameter_1_t))
{
return(new auto_vafb<return_t, parameter_1_t, void>(function));
};
template <typename return_t> vafb * craft_vafb(return_t (*function)())
{
return(new auto_vafb<return_t, void, void>(function));
};
vafb * craft_vafb(void (*function)())
{
return(new auto_vafb<void, void, void>(function));
};
struct vafb_manager
{
vafb_manager()
{
}
~vafb_manager()
{
std::map<std::string, vafb *>::const_iterator cursor(vafb_m.begin());
std::map<std::string, vafb *>::const_iterator end(vafb_m.end());
while(cursor != end)
{
delete cursor->second;
++cursor;
}
}
template <typename function_type_t> bool add(const std::string & name, std::string & output, function_type_t function)
{
const std::map<std::string, vafb *>::iterator fun(vafb_m.find(name));
if(fun != vafb_m.end())
{
output = "function already exists";
return(false);
}
vafb_m[name] = craft_vafb(function);
return(true);
}
bool process(const std::string & line, std::string & output)
{
const std::string::const_iterator cursor_line(line.begin());
const std::string::const_iterator end_line(line.end());
const std::string::const_iterator cursor_function_name(cursor_line);
const std::string::const_iterator end_function_name(std::find(cursor_function_name, end_line, ' '));
const std::string function_name(cursor_function_name, end_function_name);
const std::map<std::string, vafb *>::iterator function(vafb_m.find(function_name));
if(function == vafb_m.end())
{
output = "function not in library";
return(false);
}
const unsigned long vafb_type(function->second->vafb_type());
if(vafb::association::vfv == vafb_type)
{
output = "";
function->second->vfv();
}
if(vafb::association::sfv == vafb_type)
{
output = function->second->sfv();
}
if(vafb::association::sfs == vafb_type)
{
if(end_line == end_function_name)
{
output = "function takes one argument";
return(false);
}
const std::string::const_iterator cursor_parameter(end_function_name);
const std::string::const_iterator end_parameter(end_line);
const std::string parameter_1(cursor_parameter + 1, end_parameter);
output = function->second->sfs(parameter_1);
}
if(vafb::association::sfss == vafb_type)
{
if(end_line == end_function_name)
{
output = "function takes two arguments";
return(false);
}
const std::string::const_iterator cursor_parameter_1(end_function_name);
const std::string::const_iterator end_parameter_1(std::find(cursor_parameter_1 + 1, end_line, ' '));
const std::string::const_iterator cursor_parameter_2(end_parameter_1);
const std::string::const_iterator end_parameter_2(end_line);
const std::string parameter_1(cursor_parameter_1 + 1, end_parameter_1);
const std::string parameter_2(cursor_parameter_2 + 1, end_parameter_2);
output = function->second->sfss(parameter_1, parameter_2);
}
if(vafb::association::sfm == vafb_type)
{
std::vector<std::string> parameters;
std::string::const_iterator cursor_parameter(end_function_name);
std::string::const_iterator end_parameter(std::find(cursor_parameter + 1, end_line, ' '));
while(end_line != cursor_parameter)
{
parameters.push_back(std::string(cursor_parameter + 1, end_parameter));
cursor_parameter = end_parameter;
end_parameter = std::find(cursor_parameter + 1, end_line, ' ');
}
output = function->second->sfm(parameters);
}
return(true);
}
std::map<std::string, vafb *> vafb_m;
};
void clear_vafb()
{
std::cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
}
unsigned long random_vafb()
{
return(std::rand());
}
unsigned long gid_vafb(unsigned long value)
{
return(value ^ 0xFF00FF00);
}
double devide_vafb(double numerator, double denominato)
{
return(numerator / denominato);
}
struct my_short_test
{
friend std::ostream & operator << (std::ostream & out, const my_short_test & value)
{
out << value.value_m;
return(out);
}
friend std::istream & operator >> (std::istream & in, my_short_test & value)
{
short temp(0);
in >> temp;
value = temp;
return(in);
}
my_short_test(): value_m(0)
{
}
explicit my_short_test(short value): value_m(value)
{
}
my_short_test(const my_short_test & value): value_m(value.value_m)
{
}
my_short_test & operator = (short value)
{
value_m = value;
return(*this);
}
my_short_test & operator = (const my_short_test & value)
{
value_m = value.value_m;
return(*this);
}
my_short_test & operator += (short value)
{
value_m += value;
return(*this);
}
my_short_test & operator += (const my_short_test & value)
{
value_m += value.value_m;
return(*this);
}
short value_m;
};
my_short_test sum_vafb(const std::vector<my_short_test> & values)
{
const std::vector<std::string>::size_type size(values.size());
my_short_test temp(0);
if(0 == size)
{
return(temp);
}
for(std::vector<std::string>::size_type cursor(0); cursor < size; ++cursor)
{
temp += values[cursor];
}
return(temp);
}
int main(int argc, char ** argv)
{
std::string line;
std::string output;
vafb_manager manager;
manager.add("clear", output, clear_vafb);
manager.add("random", output, random_vafb);
manager.add("gid", output, gid_vafb);
manager.add("devide", output, devide_vafb);
manager.add("sum", output, sum_vafb);
while(std::getline(std::cin, line))
{
if(!manager.process(line, output))
{
std::cout << "error::manager:" << output << '\n';
}
else
{
if("" != output)
{
std::cout << " -> " << output << '\n';
}
}
}
return(0);
}
Posting some of those possible solutions may reveal the real solution.Quote:
Forgive me if I didn't [...] solutions.
Soma