static — преобразование лямбда-выражения c ++ в функцию c

Я пишу некоторый упаковочный код, где внешняя библиотека вызывает функцию c ++ (с использованием шаблонов с переменными значениями и т. Д.). Критическим моментом является то, что для внешней библиотеки требуется функция c, что обычно нормально, так как это допустимо:

LibraryFuncType fn = [](params) { ... }

Хотя я легко могу сделать это вручную, я хотел бы автоматизировать упаковку примерно так:

function_(context, "name", myfunc);

Для этого мне понадобится функция, похожая на:

template <ReturnType, ParamTypes...>
static void function_(Context &ctx, const std::string &name, std::function<ReturnType(ParamTypes...)> fn) {
ctx.registerFunction(name, [fn](State *state) -> int {
Context ctx(state);
return apply_helper<sizeof..(ParamTypes)>::apply(ctx, fn);
});
}

где второй параметр «ctx.registerFunction» имеет тип LibraryFuncType.

Но это, конечно, проблематично, потому что лямбда-преобразование больше не является законным из-за захвата ‘fn’. Однако, если я не перехватываю ‘fn’, у меня не будет доступа к нему в лямбде.

Я думаю, что единственный способ справиться с этим — это иметь статическую переменную, но мне не совсем понятен лучший способ ее представить. Текущее решение у меня есть:

template <typename ReturnType, typename... ParamTypes>
struct function_helper {
static std::function<ReturnType(ParamTypes...)> fn;

function_helper(std::function<ReturnType(ParamTypes...)> _fn) {
fn = _fn;
}

static void registerFn(Context &ctx, const std::string &name) {
ctx.registerFn(name, [](state *state) -> int {
Context ctx(state);
return apply_helper<sizeof...<ParamTypes>>::apply(ctx, fn);
});
}
};

template <typename ReturnType, typename... ParamTypes>
std::function<ReturnType(ParamTypes...)> function_helper<ReturnType, ParamTypes...>::fn;

template <typename ReturnType, typename... ParamTypes>
void function_(Context &ctx, const std::string &name, std::function<ReturnType(ParamTypes...)> fn) {
function_helper<ReturnType, ParamTypes...> reg(fn);
reg.registerFn(ctx, name);
}

Хотя технически это работает, это явно опасно (и хакерски), потому что, если я использую «function_helper» для двух функций с одинаковой сигнатурой, он неправильно установит «fn» для одной из них.

Кроме того, я мог бы сделать ту же опасно-статическую переменную, просто объявив статическую переменную в ‘function_’. Я организовал урок в надежде, что это поможет понять, как правильно обойти проблему.

Кто-нибудь знает лучший способ использования лямбды, которая не требует захвата (или, альтернативно, способ преобразования лямбды, которая делает захват в c-функцию)?

4

Решение

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

RegisterHelper<decltype(foo)>::doRegister<&foo>("foo");

С этим, RegisterHelper шаблон класса с static функция doRegister() который получает указатель на функцию в качестве аргумента шаблона. Было бы неплохо найти способ прямого вызова шаблона функции и выяснить его тип:

doRegister<&foo>("foo");

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

#include <string>
#include <iostream>

struct State;
typedef std::string (*function_type)(State*);
void registerFunction(std::string const& name, function_type function)
{
std::cout << "calling '" << name << "': " << function(0) << "\n";
}

template <typename T> class RegisterHelper;

template <typename RC, typename... Args>
class RegisterHelper<RC(Args...)>
{
public:
template <RC (*function)(Args...)>
static void doRegister(std::string const& name) {
registerFunction(name, [](State*) -> std::string {
return function(17, 4.0);
});
}
};

std::string foo(int, double) { return "foo"; }
std::string bar(int, double) { return "bar"; }

int main()
{

RegisterHelper<decltype(foo)>::doRegister<&foo>("foo");
RegisterHelper<decltype(bar)>::doRegister<&bar>("bar");
}
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]