Hos*_*ork 6 c++ binding variadic-templates c++11 std-function
我正在处理一个提供这种形式的钩子的C系统:
int (*EXTENSIONFUNCTION)(NATIVEVALUE args[]);
Run Code Online (Sandbox Code Playgroud)
可以注册EXTENSIONFUNCTION及其所需的参数数量.
我的想法是,我要创建一个Extension
包括扩展的类.它可以从std :: function (或任何Callable)构建,理想情况下,但我们现在只说它包含一个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;
}
Run Code Online (Sandbox Code Playgroud)
问题是,为了让C库注册并调用它,它需要基于数组的接口.: - /
我开始尝试让编译器写一个小垫片,但我没有办法做到这一点.我可以operator()
在Extension上有一个可变参数,并在NATIVEVALUE上执行运行时循环以获取Value []的数组.但是我该怎么做呢?我不能用它调用std :: function.
所以我似乎需要创建一个EXTENSIONFUNCTION实例,它调用我的std :: function,作为每个Extension实例的成员.
但基本上我发现自己靠墙,我有一个可变的模板类扩展...然后有一种"无法从这里到达"在获取这个NATIVEVALUE args[]
并能够调用std ::与他们一起工作.如果std :: function愿意用std :: array参数调用,那将解决它,但当然这不是它的工作原理.
是否有可能建立这种类型的垫片?我能做的"丑陋"事情只是代理另一个数组,如:
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;
}
Run Code Online (Sandbox Code Playgroud)
但这不符合人体工程学.似乎不可能,不知道调用约定和做某种内联汇编来处理参数和调用函数(甚至那只适用于函数,而不是一般的Callables).但是这里的人们已经证明了以前不可能实现的,通常是"那不是你想要的,你真正想要的是......"
更新:我刚刚发现这一点,这看起来很有希望......我仍在努力消化它的相关性:
(注意:在我的目标中有一些交叉问题.另一点是来自lambdas的类型推断.这里的答案似乎是最好的选择...它似乎有用,但我不知道如果它是"犹太":初始化类包含了拉姆达一个std ::功能)
如果我设法将问题简化为最简单的形式,那么您需要一种方法来调用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());
}
Run Code Online (Sandbox Code Playgroud)
这是一个演示如何使用它的示例:
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
}
Run Code Online (Sandbox Code Playgroud)
当然,对于签名int (*)(T args[])
,args
只是 aT*
并且您在编译时不知道它的大小。但是,如果您从其他地方(例如)知道编译时大小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());
}
Run Code Online (Sandbox Code Playgroud)
然后使用这样的函数:
int c_function(NATIVEVALUE args[])
{
return apply_from_array<arity>(f, args);
}
Run Code Online (Sandbox Code Playgroud)
在上面的示例中,考虑f
是 an std::function
,并且是您在编译时以某种方式设法获得arity
的 arity 。f
注意:我使用了 C++14 std::index_sequence
,但std::make_index_sequence
如果您需要代码与 C++11 一起使用,您仍然可以使用手工制作的等效项,就像您链接的我的旧问题中的indices
和。make_indices
结果:问题是关于真实代码的,它当然比上面复杂一点。扩展机制的设计使得每次调用扩展函数时,都会动态创建C API 之上的 C++ 代理( 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 {}
);
}
Run Code Online (Sandbox Code Playgroud)
applyFunc
接受该函数来调用 an 并通过使用 an和 a动态创建的底层 C API 动态地使用适当类型( Integer
、等...)的实例来调用它。String
Engine&
REBVAL*
归档时间: |
|
查看次数: |
218 次 |
最近记录: |