c++ tuple的用法

轉自:http://www.cnblogs.com/qicosmos/p/3318070.html


這次要講的內容是:c++11中的tuple(元組)。tuple看似簡單,其實它是簡約而不簡單,可以說它是c++11中一個既簡單又複雜的東東,關於它簡單的一面是它很容易使用,複雜的一面是它內部隱藏了太多細節,要揭開它神祕的面紗時又比較困難。

  tuple是一個固定大小的不同類型值的集合,是泛化的std::pair。和c#中的tuple類似,但是比c#中的tuple強大得多。我們也可以把他當做一個通用的結構體來用,不需要創建結構體又獲取結構體的特徵,在某些情況下可以取代結構體使程序更簡潔,直觀。

基本用法

構造一個tuple

tuple<const char*, int>tp = make_tuple(sendPack,nSendSize); //構造一個tuple

這個tuple等價於一個結構體

struct A
{
char* p;
int len;
};

用tuple<const char*, int>tp就可以不用創建這個結構體了,而作用是一樣的,是不是更簡潔直觀了。還有一種方法也可以創建元組,用std::tie,它會創建一個元組的左值引用。

auto tp = return std::tie(1, "aa", 2);
//tp的類型實際是:
std::tuple<int&,string&, int&>

再看看如何獲取它的值:

const char* data = tp.get<0>(); //獲取第一個值
int len = tp.get<1>(); //獲取第二個值

還有一種方法也可以獲取元組的值,通過std::tie解包tuple

int x,y;
string a;
std::tie(x,a,y) = tp; 

通過tie解包後,tp中三個值會自動賦值給三個變量。

解包時,我們如果只想解某個位置的值時,可以用std::ignore佔位符來表示不解某個位置的值。比如我們只想解第三個值時:

std::tie(std::ignore,std::ignore,y) = tp; //只解第三個值了

還有一個創建右值的引用元組方法:forward_as_tuple。

std::map<int, std::string> m;
m.emplace(std::forward_as_tuple(10, std::string(20, 'a')));

它實際上創建了一個類似於std::tuple<int&&, std::string&&>類型的tuple。

我們還可以通過tuple_cat連接多個tupe

複製代碼
int main()
{
std::tuple<int, std::string, float> t1(10, "Test", 
3.14);
int n = 7;
auto t2 = std::tuple_cat(t1, std::make_pair("Foo", 
"bar"), t1, std::tie(n));
n = 10;
print(t2);
}
複製代碼

輸出結果:

(10, Test, 3.14, Foo, bar, 10, Test, 3.14, 10)

 

  到這裏tuple的用法介紹完了,是不是很簡單,也很容易使用,相信你使用它之後就離不開它了。我前面說過tuple是簡約而不簡單。它有很多高級的用法。它和模板元關係密切,要介紹它的高級用法的時候,讀者需要一定的模板元基礎,如果你只是把它當一個泛型的pair去使用時,這部分可以不看,如果你想用它高級用法的時候就往下看。讓我們要慢慢揭開tuple神祕的面紗。

tuple的高級用法

獲取tuple中某個位置元素的類型

  通過std::tuple_element獲取元素類型。

複製代碼
template<typename Tuple>
void Fun(Tuple& tp)
{
std::tuple_element<0,Tuple>::type first = std::get<0> 
(mytuple);
std::tuple_element<1,Tuple>::type second = std::get<1> 
(mytuple);
}
複製代碼

  

獲取tuple中元素的個數:

tuple t;

int size = std::tuple_size<decltype(t))>::value;

遍歷tuple中的每個元素

  因爲tuple的參數是變長的,也沒有for_each函數,如果我們想遍歷tuple中的每個元素,需要自己寫代碼實現。比如我要打印tuple中的每個元素。

複製代碼
複製代碼
template<class Tuple, std::size_t N>
struct TuplePrinter {
    static void print(const Tuple& t)
    {
        TuplePrinter<Tuple, N - 1>::print(t);
        std::cout << ", " << std::get<N - 1>(t);
    }
};

template<class Tuple>
struct TuplePrinter<Tuple, 1>{
    static void print(const Tuple& t)
    {
        std::cout << std::get<0>(t);
    }
};

template<class... Args>
void PrintTuple(const std::tuple<Args...>& t)
{
    std::cout << "(";
    TuplePrinter<decltype(t), sizeof...(Args)>::print(t);
    std::cout << ")\n";
}
複製代碼
複製代碼

根據tuple元素值獲取其對應的索引位置

複製代碼
複製代碼
namespace detail
{
    template<int I, typename T, typename... Args>
    struct find_index
    {
        static int call(std::tuple<Args...> const& t, T&& val)
        {
            return (std::get<I - 1>(t) == val) ? I - 1 :
                find_index<I - 1, T, Args...>::call(t, std::forward<T>(val));
        }
    };

    template<typename T, typename... Args>
    struct find_index<0, T, Args...>
    {
        static int call(std::tuple<Args...> const& t, T&& val)
        {
            return (std::get<0>(t) == val) ? 0 : -1;
        }
    };
}

template<typename T, typename... Args>
int find_index(std::tuple<Args...> const& t, T&& val)
{
    return detail::find_index<0, sizeof...(Args) - 1, T, Args...>::
           call(t, std::forward<T>(val));
}

int main()
{
    std::tuple<int, int, int, int> a(2, 3, 1, 4);
    std::cout << find_index(a, 1) << std::endl; // Prints 2
    std::cout << find_index(a, 2) << std::endl; // Prints 0
    std::cout << find_index(a, 5) << std::endl; // Prints -1 (not found)
}
複製代碼
複製代碼

展開tuple,並將tuple元素作爲函數的參數。這樣就可以根據需要對tuple元素進行處理了

複製代碼
#include <tuple>




#include <type_traits> #include <utility> template<size_t N> struct Apply { 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) -> 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)); } void one(int i, double d) { std::cout << "function one(" << i << ", " << d << ");\n"; } int two(int i) { std::cout << "function two(" << i << ");\n"; return i; } //測試代碼 int main() { std::tuple<int, double> tup(23, 4.5); apply(one, tup); int d = apply(two, std::make_tuple(2)); return 0; }
複製代碼

 

  看到這裏,想必大家對tuple有了一個全面的認識了吧,怎麼樣,它是簡約而不簡單吧。對模板元不熟悉的童鞋可以不看tuple高級用法部分,不要爲看不懂而捉急,沒事的,高級部分一般用不到,知道基本用法就夠用了。

tuple和vector比較:

vector只能容納同一種類型的數據,tuple可以容納任意類型的數據;

vector和variant比較:

二者都可以容納不同類型的數據,但是variant的類型個數是固定的,而tuple的類型個數不是固定的,是變長的,更爲強大。

 

c++11 boost技術交流羣:296561497,歡迎大家來交流技術。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章