【详解】论C++的tuple

Tuple详解

定义

std::tuple<typename, ...args>

注意需要先声明头文件 include <tuple>include "tuple"

tuple 一般认为是一个不同类型元素的集合,常见用法可以用作结构体等。

基本函数

std::get

template<size_t __i, typename... _Elements>
    constexpr __tuple_element_t<__i, tuple<_Elements...>>&
    get(tuple<_Elements...>& __t) noexcept
    { return std::__get_helper<__i>(__t); }

std::get<offset>(args) 可以返回 args 的第 offset 个元素


std::make_tuple

template<typename... _Elements>
    constexpr tuple<typename __decay_and_strip<_Elements>::__type...>
    make_tuple(_Elements&&... __args)
    {
      typedef tuple<typename __decay_and_strip<_Elements>::__type...> __result_type;
      return __result_type(std::forward<_Elements>(__args)...);
    }

std::make_tuple 一般表现为 std::tuple = std::make_tuple(element...)


std::tie

  template<typename... _Elements>
    constexpr tuple<_Elements&...>
    tie(_Elements&... __args) noexcept
    { return tuple<_Elements&...>(__args...); }

std::make_tuple 相反的,可以拆分一个 std::tuple 为一堆的常量。
如果其中有不想保留的项,可以直接用 std::ignore 代替。

signed main(int argc, char *argv[]) {
    int a; char c;
    std::tuple<int, double, char> t = std::make_tuple(1, 0.1, '2'); 
    std::tie(a, std::ignore, c) = t;
    std::cout << a << std::endl; // 1
    std::cout << c << std::endl; // 2
    return 0;
}

std::forward_as_tuple

 template<typename... _Elements>
    constexpr tuple<_Elements&&...>
    forward_as_tuple(_Elements&&... __args) noexcept
    { return tuple<_Elements&&...>(std::forward<_Elements(__args)...); }

用于接受右值引用数据生成 tuple, 与 std::make_tuple 不同的是它的右值是引用的,当修改其值的时候,原来赋值所用的右值也将修改,实质上就是赋予了它地址。

注意此处 tuple 内的类型应为引用,否则相当于 std::make_tuple

signed main(int argc, char *argv[]) {
    int a = 0, c = 0;
    float b = 0.f, d = .1;

    std::tuple<int&, float&, int&, float&> tu = std::forward_as_tuple(a,b,c,d);

    std::get<0> (tu) = 2;
    std::get<1> (tu) = 4.5f;
    std::get<2> (tu) = 234;
    std::get<3> (tu) = 22.f;

    std::cout << a << std::endl; // 2
    std::cout << b << std::endl; // 4.5
    std::cout << c << std::endl; // 234
    std::cout << d << std::endl; // 22
    return 0;
}

std::tuple_cat

template<typename... _Tpls, typename = typename
           enable_if<__and_<__is_tuple_like<_Tpls>...>::value>::type>
    constexpr auto
    tuple_cat(_Tpls&&... __tpls)
    -> typename __tuple_cat_result<_Tpls...>::__type
    {
      typedef typename __tuple_cat_result<_Tpls...>::__type __ret;
      typedef typename __make_1st_indices<_Tpls...>::__type __idx;
      typedef __tuple_concater<__ret, __idx, _Tpls...> __concater;
      return __concater::_S_do(std::forward<_Tpls>(__tpls)...);
    }

此函数相当与 merge 之类的,可以将若干个 tuple 合并

signed main(int argc, char *argv[]) {
    std::tuple<int, double> a = std::make_tuple(1, 2.5);
    std::tuple<char, std::string> b = std::make_tuple('c', "F**K**F");
    auto c = std::tuple_cat(a, b);
    std::cout << std::get<0>(c) << std::endl; // 1
    std::cout << std::get<1>(c) << std::endl; // 2.5
    std::cout << std::get<2>(c) << std::endl; // c
    std::cout << std::get<3>(c) << std::endl; // F**K**F
    return 0;
}

std::swap

此项不做多余解释,只是将类型相同的两个 tuple 存储的值互换

主要可以表现为

tuple1.swap(tuple2);
std::swap(tuple1, tuple2);

std::tuple_size<type>::value

  template<typename... _Elements>
    struct tuple_size<tuple<_Elements...>>
    : public integral_constant<size_t, sizeof...(_Elements)> { };

返回一个 tuple 的大小

signed main(int argc, char *argv[]) {
    std::tuple<int, char> t = std::make_tuple(1, 'c');
    std::size_t siz = std::tuple_size<decltype(t)>::value;
    std::cout << siz << std::endl; // 2
}

tuple_element<I, type>::type

  template<size_t __i, typename _Head, typename... _Tail>
    struct tuple_element<__i, tuple<_Head, _Tail...> >
    : tuple_element<__i - 1, tuple<_Tail...> > { };

返回 tuple\(i\) 个元素的类型(注:从一个元素开始)

tuple<int, int, int, int> a(2, 3, 1, 4);
tuple_element<1, decltype(a)>::type; // int

tuple的遍历

由于 tuple 自身的原因,无法直接遍历,而 get<num>num 必须为运行前设置好的常数

所以 tuple 的遍历需要我们手写,代码如下:

template<class Tuple, std::size_t N>
struct PrintTuple {
    static void Print(const Tuple& value) {
        PrintTuple<Tuple, N - 1>::Print(value);
        std::cout << ' ' << std::get<N - 1>(value);
        return void();
    }
};

template<class Tuple>
struct PrintTuple<Tuple, 1> {
    static void Print(const Tuple& value) {
        std::cout << std::get<0>(value);
        return void();
    }
};

template<class... Args>
void TuplePrint(const std::tuple<Args...>& value) {
    PrintTuple<decltype(value), sizeof ...(Args)>::Print(value);
}
posted @ 2022-03-25 12:58  xxcxu  阅读(450)  评论(0编辑  收藏  举报