天天看点

C++ tuple

文章目录

    • tuple的使用
    • 遍历tuple
    • 模板函数中使用tuple保存函数参数

tuple属于C++11标准库函数的一部分,常用于接收不定参数。需要理解以下关键字和模板,以便理解后面的例子。

  • decltype的作用是获取变量的类型
  • typename的作用是声明后面的部分属于类型,因为在模板中是不知道它是类型还是变量的
  • remove_reference的作用是如果是引用类型只保留类型

tuple的使用

make_tuple用于构造一个tuple、tuple_size用于获取tuple的参数个数、get获取tuple指定索引的值

  • get(tuple)中的n必须是一个在编译时可以确定的常量或常量表达式,所以如果要依次获取tuple内的值,我们需要一个可变参数模板函数参数
std::tuple<double, char, std::string> t = std::make_tuple(3.14, 'A', "StoneLiu");
std::cout << "tuple length " << std::tuple_size<decltype(t)>::value;
std::cout << "first: " << std::get<0>(t) << ", two: " << std::get<1>(t) << ", three: " << std::get<2>(t) ;
           

遍历tuple

// 帮助程序用于将元组转换为可变参数模板函数参数
// sequence_generator<3>::type will be sequence<0, 1, 2>.
template <int...>
struct sequence {};
template <int N, int... S>
struct sequence_generator : sequence_generator<N - 1, N - 1, S...> {};
template <int... S>
struct sequence_generator<0, S...> {
  typedef sequence<S...> type;
};

template<typename T, typename F, int... S>
void for_each(T&& t, F f, sequence<S...>)
{
    auto l = { (f(std::get<S>(t)), 0)... };
}

template<typename... Args, typename F>
void for_each_in_tuple(std::tuple<Args...> const& t, F f)
{
    for_each(t, f, typename sequence_generator<sizeof...(Args)>::type());
}

struct functor {
    template<typename T>
    void operator()(T&& t)
    {
        std::cout << t << std::endl;
    }
};

int main()
{
    std::tuple<double, char, std::string> t = std::make_tuple(3.14, 'A', "StoneLiu");
    for_each_in_tuple(t, functor());
}
           

模板函数中使用tuple保存函数参数

这些参数在构造方法本身的时候已经确定了,封装这样的一个模板方法主要用于WebRTC里面的跨线程调用

// 帮助程序用于将元组转换为可变参数模板函数参数
// sequence_generator<3>::type will be sequence<0, 1, 2>.
template <int...>
struct sequence {};
template <int N, int... S>
struct sequence_generator : sequence_generator<N - 1, N - 1, S...> {};
template <int... S>
struct sequence_generator<0, S...> {
  typedef sequence<S...> type;
};

// The following code comes from WebRTC rtc_base bind.h
// 此结构体的功能是用于封装一个方法
template <class ObjectT, class MethodT, class R, typename... Args>
class MethodFunctor {
 public:
   // 我们在构造这个方法的时候可以传递不定参数,这些参数保存在args_中
  MethodFunctor(MethodT method, ObjectT* object, Args... args)
      : method_(method), object_(object), args_(args...) {}
  // 当我们调用()方法的时候,我们从args_中把参数依次取出来调用
  R operator()() const {
    return CallMethod(typename sequence_generator<sizeof...(Args)>::type());
  }

 private:
  // Use sequence_generator (see template_util.h) to expand a MethodFunctor
  // with 2 arguments to (std::get<0>(args_), std::get<1>(args_)), for instance.
  // S的值就类似[0, 1, 2, 3 ...],使用模板依次取出所有的参数传递给method_
  template <int... S>
  R CallMethod(sequence<S...>) const {
    return (object_->*method_)(std::get<S>(args_)...);
  }

  MethodT method_;
  typename detail::PointerType<ObjectT>::type object_;
  typename std::tuple<typename std::remove_reference<Args>::type...> args_;
};