C ++: Как передать указатель на функцию, хранящуюся в локальной переменной, в качестве параметра шаблона - PullRequest
4 голосов
/ 18 мая 2011
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;
}

Вот ошибка g ++:

main.cpp:31: error: ‘fn’ is not a valid template argument for type ‘float (*)(float)’ because function ‘fn’ has not external linkage

Из того, что я понимаю, проблема в том, что локальная переменная не имеет связи; таким образом, его нельзя использовать в качестве параметра шаблона.

Итак, я хотел знать, есть ли способ обойти эту проблему или другой метод для достижения той же цели?

Спасибо.

Редактировать 1:

Я полностью понимаю, что не могу передать значение, которое не может быть определено во время компиляции, как параметр шаблона. Я спрашиваю, есть ли лучший способ сделать это? Прямо сейчас решение, которое работает для меня:

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_;
}

и называется как:

w.wrap<float, float, &test1>("test1");
w.wrap<int, int, &test2>("test2");

Но здесь я должен передать аргумент-тип во время переноса. Есть ли способ избежать этого?

РЕДАКТИРОВАТЬ 2:

Просто для пояснения или добавления дополнительной информации: интерфейс, который я хочу представить пользователю, должен быть похож на LuaBind или Boost.Python, т.е. Wrapper.wrap ("test1", & test1); должно быть достаточно.

Ответы [ 5 ]

7 голосов
/ 18 мая 2011

Параметры шаблона должны быть известны во время компиляции, поэтому вам придется переделать код с учетом этого.

Edit: для вашего обновленного вопроса используйте 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_;
}
1 голос
/ 18 мая 2011

Как насчет использования набора классов с одноименной статической функцией-членом

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_;
}

и затем передать class Alternative в качестве параметра в этот шаблон с сайта вызова?

1 голос
/ 18 мая 2011

как насчет инкапсуляции ваших "тестовых" функций в классах, использующих общий интерфейс и затем передавающих классы в шаблоны?

0 голосов
/ 18 мая 2011

Адрес функции неизвестен во время компиляции (только позже во время компиляции), а параметры шаблона должны быть известны во время компиляции.

Обход это именно то, что вы сделали в вашемпервая функция обтекания: сделать ее параметром функции.

0 голосов
/ 18 мая 2011

Невозможно передать указатели на функции, хранящиеся в переменной, в качестве аргументов шаблона.Даже когда переменная постоянна и известна во время компиляции.Но можно передать указатель на функцию литерал :

void foo() {
}

typedef void (FunctionPtr*)();

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

и затем вызвать:

wrap<&foo>();

Я решил похожую проблему здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...