【问题标题】:Pack tuple with its index range使用索引范围打包元组
【发布时间】:2018-03-10 02:53:24
【问题描述】:

我想知道是否有办法用它的索引范围打包元组(可能使用std::index_sequence)。基本上,我想要实现的是

template <typename... Us, std::size_t... Idx>
void func(??? arg_pack) {
  // std::get<Idx>(std::move(arg_pack.args))...
}

以下内容不起作用,但表明了我的意图。

template <typename... Us, std::size_t... Idx>
struct arg_pack {
  std::tuple<Us...> args;
  std::index_sequence<Idx...> idx;
};

更新:

This 是我与sample usage 实际采用的解决方案。希望这能更清楚地说明我的意图。

【问题讨论】:

  • 有什么理由不想要template &lt;typename Tuple, std::size_t... Idx&gt; struct arg_pack { Tuple args; std::index_sequence&lt;Idx...&gt; idx; }; 吗?这种风格将支持所有的 tuple-likes,例如 std::pairstd::array

标签: c++ c++14 variadic-templates template-meta-programming stdtuple


【解决方案1】:

双可变参数列表的常见问题是:可变参数的末尾只能有一个。

我建议将索引列表打包成一个类型(通常的std::index_sequence)并将其放在首位。

我的意思是,像

template <typename...>
struct arg_pack;

template <std::size_t ... Is, typename ... Ts>
struct arg_pack<std::index_sequence<Is...>, Ts...>
 {
   static_assert( sizeof...(Is) == sizeof...(Ts) , "!" );

   std::tuple<Ts...>          args;
   std::index_sequence<Is...> idx;
 };

所以func()可以写成如下

template <std::size_t ... Is, typename ... Ts>
void func (arg_pack<std::index_sequence<Is...>, Ts...> && ap)
 {
   using unused = int[];

   (void)unused { 0, (std::get<Is>(std::move(ap.args)), 0)... };
 }

我还建议declArgPack() 的声明(不是定义,以std::declval() 的方式...但您也可以创建一个make_arg_pack() 来创建从Ts... 值列表开始的对象)declArgPack()功能

template <typename ... Ts>
arg_pack<std::make_index_sequence<sizeof...(Ts)>, Ts...> declArgPack ();

简化类型的创建,以及模板using类型的定义,简化declArgPack()的使用

template <typename ... Ts>
using arg_pack_type = decltype(declArgPack<Ts...>());

以下是一个完整的工作示例

#include <tuple>
#include <type_traits>

template <typename...>
struct arg_pack;

template <std::size_t ... Is, typename ... Ts>
struct arg_pack<std::index_sequence<Is...>, Ts...>
 {
   static_assert( sizeof...(Is) == sizeof...(Ts) , "!" );

   std::tuple<Ts...>          args;
   std::index_sequence<Is...> idx;
 };

template <typename ... Ts>
arg_pack<std::make_index_sequence<sizeof...(Ts)>, Ts...> declArgPack ();

template <typename ... Ts>
using arg_pack_type = decltype(declArgPack<Ts...>());

template <std::size_t ... Is, typename ... Ts>
void func (arg_pack<std::index_sequence<Is...>, Ts...> && ap)
 {
   using unused = int[];

   (void)unused { 0, (std::get<Is>(std::move(ap.args)), 0)... };
 }

int main ()
 {
   arg_pack_type<short, int, long, long long>  ap0;

   func(std::move(ap0));
 }

【讨论】:

  • 我会为arg_pack&lt;std::index_sequence&lt;Is...&gt;, Ts...&gt;定义一个宏。
  • @Lingxi - 宏 :( ?我开发了declArgPack() 来简化arg_pack 的定义并避免使用宏。一般建议:尽可能避免使用c-style宏。
  • @Lingxi - 答案修改:引入arg_pack_type 以简化declArgPack() 的使用。希望这会有所帮助。
  • 其实我的目的是简化func()的声明。设计的用例是对可变参数模板中的参数进行分组。
  • 即可以像func(pack_args(a, b, c), pack_args(d), pack_args(e, f))一样将多个arg_packs传递给func()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-28
  • 2021-03-02
  • 2018-11-16
  • 2016-04-04
  • 2020-06-08
  • 2017-07-12
相关资源
最近更新 更多