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