Как я могу скрыть или преобразовать boost-привязку к указателю функции C?

Предположим, что у меня есть это:

void func(WCHAR* pythonStatement) {
  // Do something with pythonStatement
}

И мне нужно преобразовать его в функцию void (void) следующим образом:

bind(func, TEXT("console.write('test')"))

Теперь у меня есть такая структура:

typedef void (__cdecl * PFUNCPLUGINCMD)();

struct FuncItem {
PFUNCPLUGINCMD pFunc;
    // ...
};

Как установить pFunc моей структуры в bind(func, "something")? Bind возвращает lambda_functor не указатель на функцию, поэтому как я могу использовать этот функтор для указателя функции?

Спасибо.


Закончено с помощью оберточного "решения" (GitHub)

Ответы

Ответ 1

Я думаю, что вы не можете, если только вы не сделаете полученный lamba_functor глобальную переменную.

В этом случае вы можете объявить функцию, которая вызывает его:

void uglyWorkaround() {
    globalLambdaFunctor();
}

и установите pFunc в uglyWorkaround().

ИЗМЕНИТЬ
Просто боковое: если вы связываете статический текст с вызовом функции, вы можете полностью опустить вызов bind() и написать:

void wrapper() {
    func(TEXT("console.write('test')"));
}

и установите pFunc в wrapper().

Ответ 2

Bind возвращает lambda_functor не указатель на функцию, поэтому как я могу использовать этот функтор для указателя функции?

Я не думаю, что ты можешь. Однако, с головы до ног, я могу представить несколько альтернатив:

  • Используйте boost::function<void()> (или std::function(), если ваш компилятор поддерживает TR1 или С++ 11) вместо void (*)().
    Он имеет возможность привязываться ко всему с несколько совместимой подписью.

  • Поместите весь код в шаблон, сделайте PFUNCPLUGINCMD параметр шаблона, и пусть аргумент аргумента функции шаблона определяет точный тип. Это вариация на первом, фактически, где вы использовали бы результат bind() непосредственно, вместо того, чтобы boost::function абстрагироваться от деталей gory.

  • Создайте оболочку, которая вызывает функтор, возвращаемый boost::bind().
    Шаблон функции может помочь компилятору определить точные типы и создать подходящую функцию, хотя я не пытался это сделать. Однако, поскольку вы не можете использовать результат bind() в качестве аргумента шаблона, но должны иметь доступ к нему, тем не менее, для этого вам понадобится глобальная переменная. (Способность избегать этого является одним из основных преимуществ функциональных объектов, очень универсальным из которых является std::function.)

  • Расширьте тип обратного вызова PFUNCPLUGINCMD, чтобы поддерживать параметр, предоставленный пользователем. Для обратных вызовов C это обычно void*. Однако, если вы передадите адрес объекта, возвращенный bind(), вашему обратному вызову, вам нужно будет преобразовать его в указатель на правильный тип, который, AFAIK, зависит от аргументов, предоставленных bind(). Чтобы этого избежать, вам нужно передать то, что абстрагирует точный тип. Опять же, std::function приходит на помощь.

Первая идея была бы лучшей, но она требует от вас возможности изменить PFUNCPLUGINCMD. Последнее может быть лучше, если PFUNCPLUGINCMD должен быть совместим с C, так как он использует общую идиому обратного вызова C.

Ответ 3

Вы не можете сделать это, если не хотите писать свой собственный компилятор Just-In-Time. В качестве альтернативы, если вы управляете кодом приема, вы можете использовать boost::function<>, который будет принимать различные типы функций, включая указатели и объекты функций, подобные тем, которые создаются с помощью boost::bind.