C++/Tuple
< C++
<Tuple> 是從C++11正式引入C++標準程式庫中的一個頭文件,定義了C++標準支持的包含固定個數的元素的容器,這些元素可以是不同數據類型。
類(模板)
編輯- tuple:類模板,實現了一種容器,包含的元素個數固定,元素可以是不同類項。是std::pair的推廣。
- tuple的初始化構造函數都是explicit,所以
tuple<int,int> t(1,2);
通過編譯而tuple<int,int> t2 ={1,2};
報錯
- tuple的初始化構造函數都是explicit,所以
- tuple_size<tuple_type>::value:類模板特化,編譯時獲得tuple、pair、array的元素個數
- tuple_element<idx,tupletype>::type:類模板特化,獲取特定元素的類型
- std::uses_allocator<std::tuple>:類模板特化,指出std::uses_allocator的type trait
常量
編輯- ignore:使用tie解開一個tuple時,跳過一個元素的占位符
函數(模板)
編輯- make_tuple:函數模板,創建一個tuple對象
- tie:函數模板,創建一個完全由左值引用作為實參而構造出的tuple,其效果相當於解開(unpack)一個tuple的當前值賦給一組單個的對象;其中不關心的元素用std::ignore對應。例如:
std::tuple<int,std::ignore,string> t(1,2,"hello");
- forward_as_tuple:函數模板,創建一個引用到實參的tuple。如果實參為右值,tuple的數據成員是右值引用;否則為左值引用。
- tuple_cat:函數模板,通過連接任意數量的tuple來創建一個tuple
std::get<size_t index>(std::tuple)
或者std::get<typename>(std::tuple)
:函數模板,訪問tuple的特定元素- operator== :函數模板,
- operator!= :函數模板,
- operator< :函數模板,
- operator<= :函數模板,
- operator> :函數模板,
- operator>= :函數模板,
- std::swap(std::tuple):函數模板,std::swap算法的特化
- apply:函數模板,C++17引入。調用一個函數,使用tuple作為實參
- make_from_tuple:函數模板,C++17引入。構造一個對象,使用tuple作為實參
例子
編輯#include <iostream>
#include <tuple>
#include <functional>
int main()
{
auto t1 = std::make_tuple(10, "Test", 3.14);
std::cout << "The value of t1 is "
<< "(" << std::get<0>(t1) << ", " << std::get<1>(t1)
<< ", " << std::get<2>(t1) << ")\n";
int n = 1;
auto t2 = std::make_tuple(std::ref(n), n);
n = 7;
std::cout << "The value of t2 is "
<< "(" << std::get<0>(t2) << ", " << std::get<1>(t2) << ")\n";
}
運行結果為:
The value of t1 is (10, Test, 3.14) The value of t2 is (7, 1)
下屬例子對於函數或成員函數f,傳入一個元組作為參數並轉化為不定長參數調用:
#include <cstddef>
#include <tuple>
#include <type_traits>
#include <utility>
template<size_t N>
struct Apply { // convert the n-element tuple to variable-length parameter
template<typename F, typename T, typename... A>
static inline auto apply(F && f, T && t, A &&... a)
-> decltype(Apply<N - 1>::apply(
::std::forward<F>(f), ::std::forward<T>(t),
::std::get<N - 1>(::std::forward<T>(t)), ::std::forward<A>(a)...
))
{
return Apply<N - 1>::apply(::std::forward<F>(f), ::std::forward<T>(t),
::std::get<N - 1>(::std::forward<T>(t)), ::std::forward<A>(a)...
);
}
};
template<>
struct Apply<0> {
template<typename F, typename T, typename... A>
static inline auto apply(F && f, T &&, A &&... a)
-> decltype(::std::forward<F>(f)(::std::forward<A>(a)...))
{
return ::std::forward<F>(f)(::std::forward<A>(a)...);
}
};
template<typename F, typename T>
inline auto apply(F && f, T && t) // call f by tuple t as parameter
-> decltype(Apply< ::std::tuple_size< typename ::std::decay<T>::type>::value
>::apply(::std::forward<F>(f), ::std::forward<T>(t)))
{
return Apply< ::std::tuple_size<typename ::std::decay<T>::type>::value
>::apply
(::std::forward<F>(f), ::std::forward<T>(t));
}
using std::forward; // You can change this if you like unreadable code or care hugely about namespace pollution.
template<size_t N>
struct ApplyMember
{
template<typename C, typename F, typename T, typename... A>
static inline auto apply(C&& c, F&& f, T&& t, A&&... a) ->
decltype(ApplyMember<N - 1>::apply(forward<C>(c), forward<F>(f), forward<T>(t), std::get<N - 1>(forward<T>(t)), forward<A>(a)...))
{
return ApplyMember<N - 1>::apply(forward<C>(c), forward<F>(f), forward<T>(t), std::get<N - 1>(forward<T>(t)), forward<A>(a)...);
}
};
template<>
struct ApplyMember<0>
{
template<typename C, typename F, typename T, typename... A>
static inline auto apply(C&& c, F&& f, T&&, A&&... a) ->
decltype((forward<C>(c)->*forward<F>(f))(forward<A>(a)...))
{
return (forward<C>(c)->*forward<F>(f))(forward<A>(a)...);
}
};
// C is the class, F is the member function, T is the tuple.
template<typename C, typename F, typename T>
inline auto apply(C&& c, F&& f, T&& t) ->
decltype(ApplyMember<std::tuple_size<typename std::decay<T>::type>::value>::apply(forward<C>(c), forward<F>(f), forward<T>(t)))
{
return ApplyMember<std::tuple_size<typename std::decay<T>::type>::value>::apply(forward<C>(c), forward<F>(f), forward<T>(t));
}