2008-11-11 2 views
21

хочу передать boost :: привязка к методу, ожидающему простого указателя функции (та же подпись).demote boost :: function to plain function pointer

typedef void TriggerProc_type(Variable*,void*); 
void InitVariable(TriggerProc_type *proc); 
boost::function<void (Variable*, void*)> triggerProc ... 
InitVariable(triggerProc); 

error C2664: 'InitVariable' : cannot convert parameter 1 from 
'boost::function<Signature>' to 'void (__cdecl *)(type *,void *)' 

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

error C2664: 'blah(void (__cdecl *)(type *,void *))' : cannot convert parameter 
1 from 'boost::_bi::bind_t<R,F,L>' to 'void (__cdecl *)(type *,void *)' 

ответ

39

Кто-нибудь заметил, что accepted answer работает только с тривиальными случаями? Единственный способ, которым функция <> :: target() возвращает объект, который может быть привязан к обратному вызову C, - это если он был сконструирован с объектом, который может быть связан с обратным вызовом C. Если это так, то вы могли бы связать его напрямую и пропустить всю функцию <> ерунда для начала.

Если вы думаете об этом, нет волшебного решения. Обратный вызов C-стиля хранится как один указатель, который указывает на исполняемый код. Для любой нетривиальной функции boost :: function <> потребуется по крайней мере два указателя: один для исполняемого кода, другой - данные, необходимые для настройки вызова (например, указатель «this» в случае связанного члена функция).

Правильный способ использования boost :: function и boost :: bind с обратными вызовами C заключается в создании функции прокладки, которая удовлетворяет сигнатуре обратного вызова, определяет, какую функцию <> позвонить и называет. Обычно обратные вызовы C будут иметь какой-то вид void * для «пользовательских данных»; вот где вы копить ваш указатель функции:

typedef void (*CallbackType)(int x, void* user_data); 
void RegisterCallback(CallbackType cb, void* user_data); 

void MyCallback(int x, void* userData) { 
    boost::function<void(int)> pfn = static_cast<boost::function<void(int)> >(userData); 
    pfn(x); 
} 

boost::function<void(int)> fn = boost::bind(myFunction(5)); 
RegisterCallback(MyCallback, &fn); 

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

11

Я думаю, что вы хотите использовать мишень() функция-член of boost :: function (не то, чтобы глоток ...)

#include <boost/function.hpp> 
#include <iostream> 

int f(int x) 
{ 
    return x + x; 
} 

typedef int (*pointer_to_func)(int); 

int 
main() 
{ 
    boost::function<int(int x)> g(f); 

    if(*g.target<pointer_to_func>() == f) { 
    std::cout << "g contains f" << std::endl; 
    } else { 
    std::cout << "g does not contain f" << std::endl; 
    } 

    return 0; 
} 
0

Вы можете заставить его работать со связыванием?

#include <boost/function.hpp> 
#include <boost/bind.hpp> 

void f(int x) 
{ 
    (void) x; 
    _asm int 3; 
} 

typedef void (*cb_t)(int); 

int main() 
{ 
    boost::function<void (int x)> g = boost::bind(f, 3); 
    cb_t cb = *g.target<cb_t>(); //target returns null 
    cb(1); 

    return 0; 
} 

обновление: Хорошо, что цель состоит в том, чтобы связать метод с функцией-обратным вызовом. Ну что теперь?

+0

единственный способ получить данные в обратном вызове, не привязывая его к нему, через бесплатный объект – 2009-02-05 04:29:21

3

can you get it working with bind?

cb_t cb = *g.target<cb_t>(); //target returns null 

Это by design. В принципе, поскольку bind возвращает совершенно другой тип, нет способа, которым это будет работать. В принципе, объект связующего прокси не может быть преобразован в указатель функции C (поскольку он не один: это объект функции). Тип, возвращаемый boost::bind, сложный. Текущий стандарт C++ не позволяет вам делать то, что вы хотите. C++ 0x будет оснащен decltype выражением, которое можно было бы использовать здесь, чтобы достичь чего-то вроде этого:

typedef decltype(bind(f, 3)) bind_t; 
bind_t target = *g.target<bind_t>(); 

Обратите внимание, что это может или не может работать. У меня нет возможности проверить это.

+0

Хорошо, что цель - связать метод с функцией-обратным вызовом. Ну что теперь? – 2009-02-04 17:04:30

+0

В принципе, вы не можете. Не использовать `boost :: bind` и` boost :: function`.Единственным средством может быть сложный код требуемой функции и получение указателя на него. – 2009-02-04 17:31:57