C++:std::tuple使用说明

目录

一、如何创建std::tuple

二、std::tuple中的元素是在堆中创建的还是在栈中创建的

三、如何获取std::tuple中存放的元素个数

四、如何获取std::tuple中存放的元素类型

五、如何遍历std::tuple中的元素

六、如何通过已有的std::tuple生成新的std::tuple

七、如何将std::tuple转化为对象

八、如何将std::tuple中的元素拆解


一、如何创建std::tuple

主要有如下4种方式:

  • std::tuple<>()
  • std::forward_as_tuple()
  • std::make_tuple()
  • std::tie()
#include <iostream>
#include <tuple>
#include <string>

using namespace std;

static int cnt = 0;

class Person {

private:
    int id; 

public:
    string name;
    int age;

    Person()  {
        id = ++cnt;
        cout << "Person()" << id <<endl;
    }

    Person(string _name, int _age): name(_name), age(_age) {
        id = ++cnt;
        cout << "Person(string _name, int _age)" << id << endl;
    }

    Person(const Person&) {
        id = ++cnt;
        cout << "Person(const Person&)" << id << endl;
    }

    Person(Person&&) {
        id = ++cnt;
        cout << "Person(Person&&)" << id << endl;
    }

    Person& operator=(const Person&) {
        cout << "operator=(const Person&)" << id << endl;

        return *this;
    }

};

int main () {
  {
    cout << "--------------------------------//(1)" << endl;
    tuple<int, bool, string, Person> t1 = tuple<int, bool, string, Person>(11, true, "ok", Person("ok", 11));
  }
  {
    cout << "--------------------------------//(2)" << endl;
    Person p("ok", 11);
    tuple<int, bool, string, Person> t2 = tuple<int, bool, string, Person>(11, true, "ok", p);
  }
  {
    cout << "--------------------------------//(3)" << endl;
    tuple<int, bool, string, Person> t3 = std::forward_as_tuple(11, true, "ok", Person("ok", 11));
  }
  {
    cout << "--------------------------------//(4)" << endl;
    Person p("ok", 11);
    tuple<int, bool, string, Person> t4 = std::forward_as_tuple(11, true, "ok", p);
  }
  {
    cout << "--------------------------------//(5)" << endl;
    tuple<int, bool, string, Person> t5 = std::make_tuple(11, true, "ok", Person("ok", 11));
  }
  {
    cout << "--------------------------------//(6)" << endl;
    Person p("ok", 11);
    tuple<int, bool, string, Person> t6 = std::make_tuple(11, true, "ok", p);
  }
    {
        cout << "--------------------------------//(7)" << endl;
        int i = 11;
        bool b = true;
        string s = "ok";
        Person p("ok", 11);
        tuple<int, bool, string, Person> t7 = std::tie(i, b, s, p);
    }
  
  return 1;
}

 执行结果如下:

--------------------------------//(1)
Person(string _name, int _age)1
Person(Person&&)2
--------------------------------//(2)
Person(string _name, int _age)3
Person(const Person&)4
--------------------------------//(3)
Person(string _name, int _age)5
Person(Person&&)6
--------------------------------//(4)
Person(string _name, int _age)7
Person(const Person&)8
--------------------------------//(5)
Person(string _name, int _age)9
Person(Person&&)10
Person(Person&&)11
--------------------------------//(6)
Person(string _name, int _age)12
Person(const Person&)13
Person(Person&&)14
--------------------------------//(7)
Person(string _name, int _age)15
Person(const Person&)16

 从执行结果可以看到,(1)(3)的效率最高,(2)(4)(7)次之,(5)更低,(6)最差。也就是说,尽量使用std::tuple<>()和std::forward_as_tuple()通过内部元素使用右值引用构造的形式;尽量不要使用std::make_tuple()的任何形式。

二、std::tuple中的元素是在堆中创建的还是在栈中创建的

std::tuple中的元素创建的区域是跟std::tuple创建的区域相同。如果std::tuple是在栈上创建的,则其中的元素也是在栈中创建的;如果std::tuple是在堆中创建的,则其中的元素也在堆中创建。

三、如何获取std::tuple中存放的元素个数

template<typename Tuple>
int getSize() {
    return std::tuple_size<Tuple>::value;
};

四、如何获取std::tuple中存放的元素类型

template<typename Tuple, int N>
struct TypeGetter
{
    using type = typename std::tuple_element<N, Tuple>::type;
};

N表示tuple中的第N个元素

五、如何遍历std::tuple中的元素

#include <iostream>
#include <tuple>
#include <string>

using namespace std;

template<typename Tuple, int N = std::tuple_size<Tuple>::value>
struct Printer
{
  static void log(Tuple& t) {
    Printer<Tuple, N - 1>::log(t);

    using type = typename std::tuple_element<N - 1, Tuple>::type;
    std::string ts = typeid(type).name();
    type& v = std::get<N - 1>(t);

    std::cout << ts << ":" << v << std::endl;
  }
};

template<typename Tuple>
struct Printer<Tuple,  1>
{
  static void log(Tuple& t) {
    using type = typename std::tuple_element<0, Tuple>::type;
    std::string ts = typeid(type).name();
    type& v = std::get<0>(t);

    std::cout << ts << ":" << v << std::endl;
  }
};

int main() {
  std::tuple<int, bool, string> t = std::forward_as_tuple(11, true, "ok");
  Printer<std::tuple<int, bool, string>>::log(t);

  return 1;
}

 执行结果:

int:11
bool:1
class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >:ok

 上述代码通过定义结构体模板Printer,并对Printer做偏特化实现对tuple对象的遍历的。

六、如何通过已有的std::tuple生成新的std::tuple

主要有以下4种形式:

  • 拷贝
  • 转移
  • 交换
  • 函数返回
tuple<int, bool, string, Person> swapTest() {
  {
    cout << "--------------------------------//(1)" << endl;
    tuple<int, bool, string, Person> t0(11, true, "ok", Person("ok", 11));
    cout << "--------------------------------" << endl;
    tuple<int, bool, string, Person> t1 = t0;  // equal to  tuple<int, bool, string, Person> t1(t0);
  }
  {
    cout << "--------------------------------//(2)" << endl;
    tuple<int, bool, string, Person> t0(11, true, "ok", Person("ok", 11));
    cout << "--------------------------------" << endl;
    tuple<int, bool, string, Person> t1 = move(t0);  // equal to  tuple<int, bool, string, Person> t1(move(t0));
  }
  {
    cout << "--------------------------------//(3)" << endl;
    tuple<int, bool, string, Person> t0(11, true, "ok", Person("ok", 11));
    cout << "--------------------------------" << endl;
    tuple<int, bool, string, Person> t1;
    cout << "--------------------------------" << endl;
    t1.swap(t0);   //  equal to  std::swap(t1, t0);    
  }

  cout << "--------------------------------//(4)" << endl;
  tuple<int, bool, string, Person> t0(11, true, "ok", Person("ok", 11));
  cout << "--------------------------------" << endl;

  return t0;
}

int main() {
  tuple<int, bool, string, Person> t = swapTest();
  cout << "--------------------------------" << endl;
  return 1;
}

运行结果:

----------------------------------------------------------------//(1)
Person(string _name, int _age)1
Person(Person&&)2
--------------------------------
Person(const Person&)3
----------------------------------------------------------------//(2)
Person(string _name, int _age)4
Person(Person&&)5
--------------------------------
Person(Person&&)6
----------------------------------------------------------------//(3)
Person(string _name, int _age)7
Person(Person&&)8
--------------------------------
Person()9
--------------------------------
Person(Person&&)10
operator=(const Person&)9
operator=(const Person&)8
----------------------------------------------------------------//(4)
Person(string _name, int _age)11
Person(Person&&)12
--------------------------------
Person(Person&&)13
--------------------------------

 从运行结果中可以看到,(2)(4)效率最高,元素都是采用转移构造函数创建的,(1)次之,(3)最差。当然(3)性能最差是有原因,它毕竟是交换,需要双向赋值。

七、如何将std::tuple转化为对象

可以使用T make_from_tuple(Tuple&& t)(C++17),并且对象要的一个类型和顺序与std::tuple中元素的类型和顺序相同的构造函数。

八、如何将std::tuple中的元素拆解

1.拆解成可变参数函数

//void print()
//{
//	cout << endl;
//}
//
//template <typename HeadType, typename... Types >
//void print(HeadType arg, Types... Args)
//{
//	cout << typeid(HeadType).name() << ":" << arg << endl;
//
//	print(Args...);
//}

template < typename Tuple, typename... Types >
constexpr void tuple_element_type(Tuple&& t, Types... Args)
{
    // print(Args...);
}

template<typename Tuple, std::size_t... I>
constexpr void tuple_element_index(Tuple&& t, std::index_sequence<I...>)
{
    tuple_element_type(t, std::get<I>(std::forward<Tuple>(t))...);
}

template <typename Tuple>
constexpr void break_tuple(Tuple&& t)
{
    tuple_element_index(t, std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
}

最终,将std::tuple中的元素拆解到方法void tuple_element_type(Tuple&& t, Types... Args)中。

2.拆解成变量

int main() {
    std::tuple<int, std::string, bool> t(121, "dds", true);

    int i;
    std::string s;
    bool b;

    std::tie(i, s, b) = t;

    cout << "i=" << i << endl;
    cout << "s=" << s << endl;
    cout << boolalpha << "b=" << b << endl;

    return 0;
}

 

  • 14
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值