Как я могу скрыть или преобразовать 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
.