我试图在_363229中存储不同数量的值,这些值稍后将用作调用与存储类型匹配的函数指针的参数 .
我创建了一个简化的示例,显示了我正在努力解决的问题:
#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();
}
通常对于涉及 std::tuple
或可变参数模板的问题,我会编写另一个模板,如 template <typename Head, typename ...Tail>
,逐个递归地评估所有类型,但我看不到这样做的方式来调度函数调用 .
这个的真正动机有点复杂,它通过 Contract 从另一个接口传递元组,所以不能改变,但是将它解压缩到函数调用的愿望是我的 . 这排除了使用 std::bind
作为避免潜在问题的廉价方法 .
什么是使用 std::tuple
调度调用的干净方法,或者是另一种更好的方法来实现存储/转发某些值和函数指针直到任意未来点的相同结果?
8 回答
这有点复杂(即使有可能) . 我建议你使用已经实现的库,即Boost.Fusion(invoke函数) . 作为奖励,Boost Fusion也与C 03编译器一起使用 .
我使用C 14 std :: index_sequence(函数返回类型作为模板参数RetT)从Johannes获得的解决方案的变体:
这是一个完整的可编辑版本的Johanne's solution到awoodland的问题,希望它可能对某人有用 . 这是用Debian挤压的g 4.7快照测试的 .
可以使用以下SConstruct文件
在我的机器上,这给了
您需要构建一个数字参数包并将其解压缩
这是一个C 14解决方案 .
这仍然需要一个辅助函数(
call_func
) . 由于这是一个常见的习惯用法,或许标准应该直接支持它作为std::call
可能的实现然后我们的延迟派遣变成了
C 17解决方案只是使用
std::apply
:只是觉得应该在这个帖子的答案中说明一次(之后它已经出现在其中一条评论中) .
此线程中仍然缺少基本的C 14解决方案 . 编辑:不,它实际上在沃尔特的答案中 .
给出了这个功能:
使用以下代码段调用它:
例:
DEMO
c++14解决方案 . 首先,一些实用工具:
这些允许您使用一系列编译时整数调用lambda .
我们完成了 .
index_upto
和index_over
允许您使用参数包而无需生成新的外部重载 .当然,在c++17你就是
现在,如果我们喜欢,在c++14我们可以写:
相对容易,并准备好发送清洁c++17语法 .
当编译器升级时,只需用
std
替换notstd
,bob就是你的叔叔 .根据给出的答案更多地思考问题,我找到了解决同一问题的另一种方法:
这需要将
delayed_dispatch()
的实现更改为:这可以通过递归将
std::tuple
转换为自己的参数包来实现 . 需要call_or_recurse
作为终止使用真实调用的递归的专门化,它只是解压缩已完成的参数包 .我不确定这是否是一个“更好”的解决方案,但它是思考和解决它的另一种方式 .
作为另一种替代解决方案,您可以使用
enable_if
来形成比我以前的解决方案更简单的东西:第一个重载只需要从元组中再获取一个参数并将其放入参数包中 . 第二个重载需要一个匹配的参数包,然后进行真正的调用,第一个重载在第二个只有第二个可行的情况下被禁用 .