“开箱"调用匹配函数指针的元组 [英] "unpacking" a tuple to call a matching function pointer
问题描述
我正在尝试在 std::tuple
中存储不同数量的值,这些值稍后将用作调用与存储类型匹配的函数指针的参数.>
我创建了一个简单的例子来展示我正在努力解决的问题:
#include #include <元组>void f(int a, double b, void* c) {std::cout <<<<":" <<<<":" <<c<<std::endl;}模板 结构 save_it_for_later {std::tuple参数;void (*func)(Args...);无效延迟调度(){//我怎样才能解压"参数来调用 func?func(std::get<0>(params), std::get<1>(params), std::get<2>(params));//但我*真的*不想写 20 个版本的 dispatch 所以我宁愿//写一些类似的东西:功能(参数...);//不合法}};int main() {int a=666;双 b = -1.234;无效 *c = NULL;save_it_for_later保存 = {std::tuple(a,b,c), f};保存.delayed_dispatch();}
通常对于涉及 std::tuple
或可变参数模板的问题,我会编写另一个模板,如 template <typename Head, typename ...Tail>
来递归评估一个接一个的所有类型,但我看不出有什么方法可以调度函数调用.
这样做的真正动机有点复杂,而且它主要只是一种学习练习.您可以假设我从另一个接口通过合同传递了元组,因此无法更改,但是将其解压缩为函数调用的愿望是我的.这排除了使用 std::bind
作为回避潜在问题的廉价方法.
使用 std::tuple
分派调用的干净方法是什么,或者实现存储/转发某些值和函数指针直到任意未来的相同净结果的替代更好方法点?
C++17 的解决方案就是简单地使用 std::apply
:
auto f = [](int a, double b, std::string c) { std::cout<<a<<" "<<b<<" "<<c<<std::endl;};自动参数 = std::make_tuple(1,2.0,"你好");std::apply(f, params);
只是觉得应该在此线程的答案中说明一次(在它已经出现在其中一条评论中之后).
<小时>该线程中仍然缺少基本的 C++14 解决方案.不,它实际上在 Walter 的回答中.
给出这个函数:
void f(int a, double b, void* c){std::cout <<<<":" <<<<":" <<c<<std::endl;}
使用以下代码段调用它:
template自动调用(函数 f,元组 t,std::index_sequence<I ...>){返回 f(std::get(t) ...);}template自动调用(函数 f,元组 t){静态 constexpr 自动大小 = std::tuple_size::value;return call(f, t, std::make_index_sequence{});}
示例:
int main(){std::tuplet;//或 std::arrayt;//或 std::pairt;调用(f, t);}
I'm trying to store in a std::tuple
a varying number of values, which will later be used as arguments for a call to a function pointer which matches the stored types.
I've created a simplified example showing the problem I'm struggling to solve:
#include <iostream>
#include <tuple>
void f(int a, double b, void* c) {
std::cout << a << ":" << b << ":" << c << std::endl;
}
template <typename ...Args>
struct save_it_for_later {
std::tuple<Args...> params;
void (*func)(Args...);
void delayed_dispatch() {
// How can I "unpack" params to call func?
func(std::get<0>(params), std::get<1>(params), std::get<2>(params));
// But I *really* don't want to write 20 versions of dispatch so I'd rather
// write something like:
func(params...); // Not legal
}
};
int main() {
int a=666;
double b = -1.234;
void *c = NULL;
save_it_for_later<int,double,void*> saved = {
std::tuple<int,double,void*>(a,b,c), f};
saved.delayed_dispatch();
}
Normally for problems involving std::tuple
or variadic templates I'd write another template like template <typename Head, typename ...Tail>
to recursively evaluate all of the types one by one, but I can't see a way of doing that for dispatching a function call.
The real motivation for this is somewhat more complex and it's mostly just a learning exercise anyway. You can assume that I'm handed the tuple by contract from another interface, so can't be changed but that the desire to unpack it into a function call is mine. This rules out using std::bind
as a cheap way to sidestep the underlying problem.
What's a clean way of dispatching the call using the std::tuple
, or an alternative better way of achieving the same net result of storing/forwarding some values and a function pointer until an arbitrary future point?
The C++17 solution is simply to use std::apply
:
auto f = [](int a, double b, std::string c) { std::cout<<a<<" "<<b<<" "<<c<< std::endl; };
auto params = std::make_tuple(1,2.0,"Hello");
std::apply(f, params);
Just felt that should be stated once in an answer in this thread (after it already appeared in one of the comments).
The basic C++14 solution is still missing in this thread. EDIT: No, it's actually there in the answer of Walter.
This function is given:
void f(int a, double b, void* c)
{
std::cout << a << ":" << b << ":" << c << std::endl;
}
Call it with the following snippet:
template<typename Function, typename Tuple, size_t ... I>
auto call(Function f, Tuple t, std::index_sequence<I ...>)
{
return f(std::get<I>(t) ...);
}
template<typename Function, typename Tuple>
auto call(Function f, Tuple t)
{
static constexpr auto size = std::tuple_size<Tuple>::value;
return call(f, t, std::make_index_sequence<size>{});
}
Example:
int main()
{
std::tuple<int, double, int*> t;
//or std::array<int, 3> t;
//or std::pair<int, double> t;
call(f, t);
}
这篇关于“开箱"调用匹配函数指针的元组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!