Подтвердить что ты не робот

Demote boost:: function to plain function pointer

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

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 *)'

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

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

Ответ 1

Кто-нибудь заметил, что принятый ответ работает только с тривиальными случаями? Единственный способ, которым функция < > :: 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);

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

Ответ 2

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

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

Ответ 3

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

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

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

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

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

Ответ 5

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

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

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