doFun(f1) works just fine. You have a typo in the first getVal should be setVal, but otherwise, yes, it should work.
Printable View
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