C++: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中存放的元素個數
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)效能最差是有原因,它畢竟是交換,需要雙向賦值。