using namespace std;
float test1(float i){
return i * i;
}
int test2(int i){
return i+9;
}
struct Wrapper{
typedef void (*wrapper_type)(int);
template<class R, class A>
void wrap(string name,R (*fn) (A) ){
wrapper_type f_ = &Wrapper::wrapper1<R,A,fn>;
// in the real program, f_ would be passed in an array to some c library
wrappers[name] = f_;
}
void run(int i){
map<string,wrapper_type>::iterator it, end = wrappers.end();
for(it=wrappers.begin();it!=end;it++){
wrapper_type wt = (*it).second;
(*wt)(i);
}
}
template<class R, class A, R (*fn) (A)>
static void wrapper1(int mul){
//do something
A arg = mul;
R result = (*fn)( arg );
cout << "Result: " << result << endl;
}
map<string,wrapper_type> wrappers;
};
int main(int argc, char** argv) {
Wrapper w;
w.wrap("test1",&test1);
w.wrap("test2",&test2);
w.run(89);
return 0;
}
Here's the g++ error:
main.cpp:31: error: ‘fn’ is not a valid template argument for type ‘float (*)(float)’ because function ‘fn’ has not external linkage
From what i understand, the problem is that a local variable has no linkage; thus it can not be used as a template parameter.
So, i wanted to know if there's a way to get around this problem or another technique to accomplish the same ?
Thanks.
Edit 1:
I totally understand that I can't pass a value that can not be determined at compile time as a template paramter. What i'm asking is - is there a better way to do this? Right now the solution that works for me is :
template<class R, class A,R (*fn) (A)>
void wrap(string name){
wrapper_type f_ = &Wrapper::wrapper1<R,A,fn>;
// in the real program, f_ would be passed in an array to sm c library
wrappers[name] = f_;
}
and called as :
w.wrap<float, float, &test1>("test1");
w.wrap<int, int, &test2>("test2");
But here I've to pass argument-type during wrapping. Is there someway to avoid this ?
EDIT 2:
Just to clarify or add more info: The interface I want to present to the user has to be similar to LuaBind or Boost.Python i.e. Wrapper.wrap("test1",&test1); should be sufficient.
Template parameters must be known at compile time, so you'll have to redesign your code taking this into account.
Edit: for your updated question use Boost function_traits.
How about using a set of classes with a same named static member function
and then pass
class Alternative
as a parameter into that template from the call site?what about encapsulating your "test*" functions in classes sharing a common interface and then passing the classes into the templates?
The address of a function is not known during compile time (only later at link time), and template parameters must be known at compile time.
The way around this is exactly what you have done in your first wrap function: Make it a function parameter.
It is not possible to pass function pointers stored in a variable as a template arguments. Even when the variable is constant and known at compile time. But it is possible to pass a function pointer literal:
and then call:
I have solved similar problem here.