понизить boost :: function для простого указателя на функцию - PullRequest
21 голосов
/ 12 ноября 2008

хочу передать 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 :: function и просто передать связанный функтор напрямую, но тогда я получаю похожую ошибку:

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

Ответы [ 5 ]

41 голосов
/ 11 августа 2010

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

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

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

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 голосов
/ 12 ноября 2008

Я думаю, что вы хотите использовать функцию-член target () в 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;
}
3 голосов
/ 04 февраля 2009

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

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

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

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

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

2 голосов
/ 27 февраля 2009
0 голосов
/ 04 февраля 2009

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

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

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

...