跳至內容

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_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));
}