我正在编写一些包装代码,其中外部库调用 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”,lambda 转换不再合法。但是,如果我不捕获“fn”,那么我将无法在 lambda 中访问它。
我认为解决这个问题的唯一方法是拥有一个静态变量,但我不清楚引入它的最佳方法。我目前的解决方案是:
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_”中声明一个静态变量来执行相同的危险静态变量。我开设了这门课,希望它能让人们对解决问题的正确方法有所了解。
有谁知道使用不需要捕获的 lambda 的更好方法(或者,一种将捕获的 lambda 转换为 c 函数的方法)?