现在的位置: 首页 > 算法 > 正文

如何使用tuple和vector解包当做参数传入到函数中

2020年01月15日 算法 ⁄ 共 534字 ⁄ 字号 评论关闭

  在C++中,有一些情况下,我们需要将tuple或者vector中的值当做参数传递到一个函数当中,传统的做法如下:

  std::vector< int> v;

  call(v[0], v[1], v[2]);

  auto r = std::make_tuple(1, 2.1, 1ull)

  call(std::get<0>(r), std::get<1>(r), std::get<2>(r));

  我们可以通过如下的方式,将tuple解包传入到函数当中:

  #include < iostream>

  #include < tuple>

  template struct index_sequence { };

  template struct make_index_sequence_helper : make_index_sequence_helper { };

  template struct make_index_sequence_helper <0, S...> { typedef index_sequence type; };

  template using make_index_sequence = typename make_index_sequence_helper::type;

  int test(int a, double b) {

  std::cout << a << " " << b << std::endl;   }   template   void callFuncHelper(F f, index_sequence, T&& t) {   f(std::get(t)...);   }   template   void callFunc(F f, const std::tuple& t) {   callFuncHelper(f, make_index_sequence(), t);   }   int main() {   auto inp = std::make_tuple(0, 1.23);   callFunc(test, inp);   }   前面第一段通过继承机制提供了一个make_index_sequence的模板类,C++14中可以直接使用这个模板类,c++11中需要自己来实现,它是通过继承的方案实现的:   假如N = 4, 那么:   make_index_sequence_helper<4>: make_index_sequence_helper<3, 3>;

  make_index_sequence_helper<4, 4>: make_index_sequence_helper<2, 2, 3>;

  make_index_sequence_helper<2, 2, 3>:make_index_sequence_helper<1, 1, 2, 3>;

  make_index_sequence_helper<1, 1, 2, 3>:make_index_sequence_helper<0, 0, 1, 2, 3>;

  make_index_sequence_helper<0, 0, 1, 2, 3> {

  typedef index_sequence<0, 1, 2, 3> type;

  }

  test是一个测试函数,callFunc需要两个输入分别是被调用的函数f和一个tuple的参数t,它负责对函数进行调用。它计算出tuple中的元素个数,构造出一个index_sequence传递到callFuncHelper中,由该函数调用std::get对tuple进行解包

  我们可以通过如下的方式,将vector解包传入到函数当中

  #include < iostream>

  #include < vector>

  int test(int a, int b) {

  std::cout << a << " " << b << std::endl;   }   template   typename std::enable_if::type   callFunc(F f, const std::vector& v, Args&&... args) {   f(std::forward(args)...);   }   template   typename std::enable_if::type   callFunc(F f, const std::vector& v, Args&&... args) {   callFunc(test, v, v[N - 1], std::forward(args)...);   }   int main() {   std::vector inp{1, 2};   callFunc<2>(test, inp);

  }

  test还是我们要测试的函数,前面的callFunc利用了sfinae准则,当N为0的时候,只能对第一个函数进行特化;当N不为0的时候,只能对第二个函数进行特化;通过这种方式,可以将vector进行解包当做参数传到func当中。

  当N = n时,解析第n-1个参数,并放在上一轮解析的参数之前,传给下一轮;当N = 0时,对传入的函数进行调用。

  需要注意的是,vector的长度必须是在编译期就已知的,或者我们只想取该vector的前某几个参数传到对应的函数中。

  当然如果你觉得这个示例中的<2>起来看着不舒服的话,也可以写一个辅助函数,获取test函数的参数数量,然后将这个数量当做模板参数传到callFunc中。

  最后,根据上面所述的原理,提供一种tuple转list的方式,并且允许转换的过程中进行一系列的转化操作,编译的时候需要加上-std=c++14:

  #include < tuple>

  #include < utility>

  #include < iostream>

  #include < vector>

  template

  T transfer(T a, T b) {

  return a * b;

  }

  template

  std::vector helper(std::index_sequence, const std::tuple& tp) {

  return std::vector{transfer(std::get(tp), 3)...};

  }

  template

  std::vector tupleToList(const std::tuple& tp) {

  return helper(std::make_index_sequence(), tp);

  }

  int main() {

  auto tp = std::make_tuple(1, 2, 3);

  auto r = tupleToList(tp);

  for (auto i : r) {

  std::cout << i << std::endl;   }   }

抱歉!评论已关闭.