在 C++ 中解包 std::vector 作为函数参数demo

您所在的位置:网站首页 pack解包 在 C++ 中解包 std::vector 作为函数参数demo

在 C++ 中解包 std::vector 作为函数参数demo

2023-03-01 04:34| 来源: 网络整理| 查看: 265

在 C++ 中解包 std::vector 作为函数参数

转载于 https://liam.page/2019/07/04/unpack-vector-as-parameters-for-functions/ 修正了一些typo

有一个接受若干个同类型参数的函数 template U func(T a, T b, T c),现在有一个 std::vector args,希望将 std::vector 当中的元素作为函数参数传进去,要怎么办。

这篇来解决这个问题。

首先,待执行的函数的参数个数,在编译时就能知道;比如这里是 3 个。于是,很自然地,我们最终肯定需要类似这样的代码:

现在的问题是,我们希望这种调用代码能够自动生成,而不是手动去写。因为 func 的参数,在实际情况下,可能不止 3 个。C++ 11 引入了参数包(parameter pack)的概念,能够将若干个模板参数,打包在一起,然后再用 ... 的方式展开。参数包可以是类型参数包,比如 template ,这样 (*Args)... 就是各个类型的指针;参数包也可以是变量参数包,比如 size_t... I,这样 args[I]... 就是 args[0], args[1], args[2] 这样的展开。后者正是我们要的。

于是,为了利用参数包,我们首先需要根据函数 func 的参数数量,构建一个参数包,作为索引。

namespace util { template struct indices { using next = indices; }; template struct build_indices { using type = typename build_indices::type::next; }; template struct build_indices { using type = indices; }; template using BuildIndices = typename build_indices::type; } // namespace util

这里用到了递归的cpp函数模板提到过的技巧。我们看:

BuildIndices 是 build_indices::type 也就是全特化的 indices;BuildIndices 是 build_indices::type 也就是 build_indices::type::next 也就是 indices::next 也就是 indices;同理,BuildIndices 是 build_indices::type 也就是 build_indices::type::next 也就是 build_indices::type::next::next 也就是 indices::next 也就是 indices;以此类推 BuildIndices 是 indices。

于是我们很容易构建出 caller 如下:

template void call(Func& func, std::vector& args, indices) { f(args[I]...) }

使用时只需要这样既可:

我们将整个封装起来,写成一个完整的例子如下:

#include #include #include namespace util { template struct indices { using next = indices; }; template struct build_indices { using type = typename build_indices::type::next; }; template struct build_indices { using type = indices; }; template using BuildIndices = typename build_indices::type; template struct unpack_caller { private: template returnT call(FuncType& f, std::vector& args, indices) { return f(args[I]...); } public: template returnT operator()(FuncType& f, std::vector& args) { return call(f, args, BuildIndices()); } }; } // namespace util int func(int a, int b, int c) { return a + b + c; } int main() { std::vector args = {1, 2, 3}; int i = util::unpack_caller()(func, args); std::cout using type = typename std::tuple_element::type; }; }; template struct function_traits_impl; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits : function_traits_impl {}; template struct function_traits : function_traits_impl {};

这里,function_traits_defs 是 traits 的具体定义,function_traits_impl 则是针对各种情况(函数、函数指针、仿函数的各种 cv 修饰符及引用情况)做的实现,function_traits 则是暴露在外面的接口。如此一来,我们可以对 util::unpack_caller 做一些改进。

namespace details { template ReturnT do_call(FuncType& func, VecType& args, indices ) { return func(args[I]...); } } // namespace details template ReturnT unpack_call(FuncType& func, VecType& args) { return details::do_call(func, args, BuildIndices()); }

如此一来,完整的示例如下:

#include #include #include namespace util { template struct function_traits_defs { static constexpr size_t arity = sizeof...(Args); using result_type = ReturnType; template struct arg { using type = typename std::tuple_element::type; }; }; template struct function_traits_impl; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits_impl : function_traits_defs {}; template struct function_traits : function_traits_impl {}; template struct function_traits : function_traits_impl {}; template struct indices { using next = indices; }; template struct build_indices { using type = typename build_indices::type::next; }; template struct build_indices { using type = indices; }; template using BuildIndices = typename build_indices::type; namespace details { template ReturnT do_call(FuncType& func, VecType& args, indices) { return func(args[I]...); } } // namespace details template ReturnT unpack_caller(FuncType& func, VecType& args) { return details::do_call(func, args, BuildIndices()); } } // namespace util int func(int a, int b, int c) { return a + b + c; } int main() { std::vector args = {1, 2, 3}; int j = util::unpack_caller(func, args); std::cout


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3