将 std::function 代理为需要参数数组的 C 函数
Proxying a std::function to a C function that wants an array of arguments
我正在处理一个提供这种形式的钩子的 C 系统:
int (*EXTENSIONFUNCTION)(NATIVEVALUE args[]);
可以注册一个 EXTENSION 函数及其所需的参数数量。
我的想法是,我会创建一个类Extension
来包装扩展。 它将能够从一个std::function(或任何可调用的,理想情况下,但让我们说它现在包含一个std::function(。 扩展采用 Value 参数,这些参数包装了 NATIVEVALUE(但更大(。 例如,我会自动处理sizeof...(Ts)
参数计数。 它可能看起来像这样:
Extension<lib::Integer, lib::String> foo =
[](lib::Integer i, lib::String s) -> int {
std::cout << i;
std::cout << s;
return 0;
}
问题是,为了让 C 库注册和调用它,它需要基于数组的接口。 :-/
我开始尝试让编译器编写一个小填充程序,但我看不到这样做的方法。 我可以在扩展上有一个可变参数operator()
,并在 NATIVEVALUE 上执行运行时循环以获取 Value[] 数组。 但是我该怎么办呢? 我不能用它调用std::function。
因此,我似乎需要创建一个调用我的std::function的EXTENSIONFUNCTION实例作为每个扩展实例的成员。
但基本上我发现自己碰壁了,在那里我有一个用于扩展的可变参数模板类......然后是一种"无法从这里到达那里",就接受这个NATIVEVALUE args[]
并能够与他们一起调用 std::function。 如果 std::function 愿意用 std::数组参数来调用,那将解决它,但当然这不是它的工作方式。
是否可以构建这种类型的垫片? 我能做的"丑陋"的事情就是代理到另一个数组,比如:
Extension<2> foo =
[](lib::Value args[]) -> int {
lib::Integer i (args[0]);
lib::String s (args[1]);
std::cout << i;
std::cout << s;
return 0;
}
但这不符合人体工程学。 这似乎是不可能的,不知道调用约定并做一些内联汇编的东西来处理参数和调用函数(甚至这仅适用于函数,而不是一般的可调用对象(。 但这里的人以前已经证明了不可能的可能,通常是通过"那不是你想要的,你真正想要的是......">
更新:我刚刚发现这个,这似乎很有希望...我仍在努力消化它的相关性:
"解包"元组以调用匹配函数指针
(注:我打算做的事情有几个交叉问题。 另一点是来自 lambda 的类型推断。 这里的答案似乎是最好的选择...它似乎有效,但我不知道它是否是"犹太洁食":初始化包含 std::函数的类 lambda (
如果我设法将问题简化为最简单的形式,则需要一种方法来调用std::function
从固定大小的 C 样式数组中获取其参数,而无需创建运行时循环。然后,这些函数可能会解决您的问题:
template<std::size_t N, typename T, typename F, std::size_t... Indices>
auto apply_from_array_impl(F&& func, T (&arr)[N], std::index_sequence<Indices...>)
-> decltype(std::forward<F>(func)(arr[Indices]...))
{
return std::forward<F>(func)(arr[Indices]...);
}
template<std::size_t N, typename T, typename F,
typename Indices = std::make_index_sequence<N>>
auto apply_from_array(F&& func, T (&arr)[N])
-> decltype(apply_from_array_impl(std::forward<F>(func), arr, Indices()))
{
return apply_from_array_impl(std::forward<F>(func), arr, Indices());
}
下面是一个演示如何使用它的示例:
auto foo = [](int a, int b, int c)
-> int
{
return a + b + c;
};
int main()
{
Value arr[] = { 1, 2, 3 };
std::cout << apply_from_array(foo, arr); // prints 6
}
当然,使用签名int (*)(T args[])
,args
只是一个T*
,您在编译时不知道它的大小。但是,如果您从其他地方(例如从std::function
(知道编译时大小,您仍然可以调整apply_from_array
以手动提供编译时大小信息:
template<std::size_t N, typename T, typename F, std::size_t... Indices>
auto apply_from_array_impl(F&& func, T* arr, std::index_sequence<Indices...>)
-> decltype(std::forward<F>(func)(arr[Indices]...))
{
return std::forward<F>(func)(arr[Indices]...);
}
template<std::size_t N, typename T, typename F,
typename Indices = std::make_index_sequence<N>>
auto apply_from_array(F&& func, T* arr)
-> decltype(apply_from_array_impl<N>(std::forward<F>(func), arr, Indices()))
{
return apply_from_array_impl<N>(std::forward<F>(func), arr, Indices());
}
然后像这样使用函数:
int c_function(NATIVEVALUE args[])
{
return apply_from_array<arity>(f, args);
}
在上面的示例中,请考虑f
是一个std::function
,arity
是您在编译时设法以某种方式获得的f
的稀有性。
注意:我使用了 C++14 std::index_sequence
和std::make_index_sequence
但如果您需要代码使用 C++11,您仍然可以使用手工制作的等价物,例如您链接的旧问题中的 indices
和 make_indices
。
后果:问题是关于真正的代码,当然比上面复杂一点。扩展机制的设计使得每次调用扩展函数时,C++ C API 之上的代理(lib::Integer
、lib::String
等(都会动态创建,然后传递给用户定义的函数。这需要一种新的方法,applyFunc
Extension
:
template<typename Func, std::size_t... Indices>
static auto applyFuncImpl(Func && func,
Engine & engine,
REBVAL * ds,
utility::indices<Indices...>)
-> decltype(auto)
{
return std::forward<Func>(func)(
std::decay_t<typename utility::type_at<Indices, Ts...>::type>{
engine,
*D_ARG(Indices + 1)
}...
);
}
template <
typename Func,
typename Indices = utility::make_indices<sizeof...(Ts)>
>
static auto applyFunc(Func && func, Engine & engine, REBVAL * ds)
-> decltype(auto)
{
return applyFuncImpl(
std::forward<Func>(func),
engine,
ds,
Indices {}
);
}
applyFunc
函数使用具有Engine&
和REBVAL*
动态创建的底层 C API 动态调用具有适当类型(Integer
、String
等(的实例调用它。
- C++函数模板需要 &for 数组参数
- C++ 数组参数不起作用
- 使用数组参数进行函数专用化
- 为什么我的数组参数的方法无法正常工作?(C )
- SWIG - Java 代理类数组参数
- 在 gcc 中使用数组参数编译外部"c"代码
- 从 VB6 调用的 C++ DLL 函数中的输出数组参数
- 如何根据数组参数项类型重载 IDL 中的函数
- 引用谷歌测试/模拟框架中的数组参数
- C++将数组参数传递给函数
- 字符星形数组参数未正确终止
- 如何将德尔菲的"字符串数组"参数翻译成C++?
- 为什么 gcc 无法推断数组参数的模板化大小?(C++11)
- 使用 const char 数组参数分析 constexpr 显示运行时执行
- C++指针数组参数
- 固定大小的多维数组参数
- 为什么数组参数被视为常量数组
- 如何在pgsql中格式化数组参数
- C++字符数组参数在x86编译中包含奇怪的字符
- 对象数组参数 - 错误:字段“字母”的类型不完整