C++ : How to pass function pointer, stored in a lo

2019-06-26 16:36发布

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.

5条回答
女痞
2楼-- · 2019-06-26 16:41

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.

template<R (*fn) (A)>
void wrap(string name){
    wrapper_type f_ = &Wrapper::wrapper1<function_traits<A>::result_type, function_traits<A>::arg1_type,fn>;
    // in the real program, f_ would be passed in an array to sm c library
    wrappers[name] = f_;
}
查看更多
Luminary・发光体
3楼-- · 2019-06-26 16:43

How about using a set of classes with a same named static member function

struct FirstAlternative {
    static void DoStuff();
};

struct SecondAlternative {
    static void DoStuff();
};

template<class R, class A, class Alternative>
void wrap(string name) (A) ){
    wrapper_type f_ = &Wrapper::wrapper1<R,A,&Alternative::DoStuff>;
    wrappers[name] = f_;
}

and then pass class Alternative as a parameter into that template from the call site?

查看更多
贼婆χ
4楼-- · 2019-06-26 16:51

what about encapsulating your "test*" functions in classes sharing a common interface and then passing the classes into the templates?

查看更多
小情绪 Triste *
5楼-- · 2019-06-26 16:57

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.

查看更多
姐就是有狂的资本
6楼-- · 2019-06-26 16:58

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:

void foo() {
}

typedef void (FunctionPtr*)();

template<FunctionPtr F>
void wrap() {
    F();
}

and then call:

wrap<&foo>();

I have solved similar problem here.

查看更多
登录 后发表回答