如何将tuple元素拆包作为参数与之匹配的静态函数的入参
实现方案
以下是不同C++标准下的实现方式,所有实现均在编译期完成参数匹配,无运行时额外开销,且会自动校验tuple元素和函数入参的类型、数量是否匹配。
C++17及以上版本
直接使用标准库内置的std::apply即可,该工具就是专门为tuple拆包调用普通函数设计的:
#include <tuple> #include <iostream> #include <string> // 普通静态参数函数,非可变参数模板 void print(int a, double b, const std::string& c) { std::cout << a << " | " << b << " | " << c << std::endl; } int main() { std::tuple<int, double, std::string> param_tuple = {10, 2.718, "test string"}; // 直接拆包tuple传入函数 std::apply(print, param_tuple); return 0; }
C++11/14版本
标准库未内置std::apply,需要自己基于编译期索引序列实现展开逻辑:
#include <tuple> #include <iostream> #include <string> #include <utility> // 目标静态参数函数 void print(int a, double b, const std::string& c) { std::cout << a << " | " << b << " | " << c << std::endl; } // C++11 自定义编译期索引序列(C++14可直接用std::index_sequence,省略这部分定义) template <size_t... Indices> struct index_sequence {}; template <size_t N, size_t... Indices> struct make_index_sequence : make_index_sequence<N-1, N-1, Indices...> {}; template <size_t... Indices> struct make_index_sequence<0, Indices...> : index_sequence<Indices...> {}; // 内部展开逻辑 template <typename Func, typename Tuple, size_t... Indices> auto apply_impl(Func&& func, Tuple&& t, index_sequence<Indices...>) -> decltype(func(std::get<Indices>(std::forward<Tuple>(t))...)) { return func(std::get<Indices>(std::forward<Tuple>(t))...); } // 对外调用接口 template <typename Func, typename Tuple> auto apply(Func&& func, Tuple&& t) -> decltype(apply_impl(std::forward<Func>(func), std::forward<Tuple>(t), make_index_sequence<std::tuple_size<typename std::decay<Tuple>::type>::value>())) { constexpr size_t tuple_size = std::tuple_size<typename std::decay<Tuple>::type>::value; return apply_impl(std::forward<Func>(func), std::forward<Tuple>(t), make_index_sequence<tuple_size>()); } int main() { std::tuple<int, double, std::string> param_tuple = {10, 2.718, "test string"}; apply(print, param_tuple); return 0; }
扩展说明
- 该实现支持完美转发,临时tuple的元素会直接移动到函数入参,不会产生额外拷贝
- 除普通函数外,也支持lambda、仿函数、类成员函数(调用成员函数时需要把类实例作为tuple的第一个元素传入即可)
- 如果tuple元素和函数入参不匹配,会直接触发编译错误,不会留到运行时报错
内容的提问来源于stack exchange,提问作者Bonita Montero
相关产品推荐
相关产品推荐

