如何从可变参数模板生成std::function类型的std::tuple
解决方案
首先,你要的函数模板声明可以直接靠模板参数推导实现,不用复杂操作:
template <typename... Ts> void f(std::tuple<Ts...>& data, std::tuple<std::function<void(Ts&)>...> functions);
当你传入std::tuple<int, std::string>&这类参数作为第一个参数时,第二个参数会自动被推导为对应类型的std::function元组——比如上面的例子就会推导成std::tuple<std::function<void(int&)>, std::function<void(std::string&)>>,完全符合你的需求。
如果需要在函数内部遍历两个元组,用对应位置的函数处理data里的元素,这时候才需要用到std::index_sequence来展开参数包,具体实现分两步:
1. 写辅助展开函数
我们需要一个带索引序列的辅助函数,用来逐个访问元组元素:
template <typename... Ts, std::size_t... Idx> void f_impl(std::tuple<Ts...>& data, const std::tuple<std::function<void(Ts&)>...>& functions, std::index_sequence<Idx...>) { // 用C++17折叠表达式逐个调用函数,传入对应元素的引用 (std::get<Idx>(functions)(std::get<Idx>(data)), ...); }
这里的折叠表达式(...,)会把每个索引对应的函数调用依次展开执行,简洁高效。
2. 对外的主函数
主函数负责生成匹配的索引序列,然后把调用转发给辅助函数:
template <typename... Ts> void f(std::tuple<Ts...>& data, std::tuple<std::function<void(Ts&)>...> functions) { // 自动生成0到元素数量-1的索引序列 f_impl(data, functions, std::index_sequence_for<Ts...>()); }
std::index_sequence_for<Ts...>会根据模板参数包的大小,生成刚好匹配元组元素数量的索引序列,不用手动写索引。
实际使用示例
#include <tuple> #include <functional> #include <iostream> // 把上面的函数实现放在这里 int main() { std::tuple<int, std::string> data{42, "hello"}; auto functions = std::make_tuple( [](int& num) { num *= 2; }, [](std::string& str) { str += " world"; } ); f(data, functions); // 输出:82 hello world std::cout << std::get<0>(data) << " " << std::get<1>(data) << std::endl; return 0; }
额外说明
- 如果你的编译器不支持C++17,可以用递归展开的方式替代折叠表达式,但折叠表达式写法更简洁。
std::index_sequence是C14的特性,要是需要兼容C11,自己写个简单的索引序列模板也不难。
内容的提问来源于stack exchange,提问作者canellas
相关产品推荐
相关产品推荐

