1. 程式人生 > >C++11::遍歷tuple中的元素

C++11::遍歷tuple中的元素

轉自:https://blog.csdn.net/lanchunhui/article/details/49868077

在設計tuple的遍歷程式之前,我們不妨先進行std::pair的列印工作:

// #include <utility>
cout << make_pair("InsideZhang", 23) << end;
            // ("InsideZhang", 23)

為了實現上述的功能,我們需要過載<<運算子。

template<typename T1, typename T2>
std::ostream& pair_print(std::ostream& os, const pair<T1, T2>& p)
{
    return os << "(" << p.first << ", " << p.second << ")";
}
  •  

當我們試圖仿照上例的形式實現對tuple的遍歷輸出時:

template<typename... Args>
std::ostream& operator<<(std::ostream& os, const std::tuple<Args...>& t)
{
    os << "(" << std::get<0>(t);
    for (size_t i = 1; i < sizeof...(Args) << ++i)
        os << ", " << std::get<i>(t);
    return os << "]";
}

int main(int, char**)
{
    cout << make_tuple("InsideZhang", 23, "HeNan") << endl;
            // 編譯出錯,區域性變數i不可作為非型別模板引數
    return 0;
}
  •  

這時我們便需要單獨把每一位的索引拿出來作為非型別模板引數進行遞迴呼叫:

template<typename Tuple>
void tuple_print(const Tuple& t, size_t N, std::ostream& os)
{
    if (N != 1)
        tuple_print(t, N-1, os);
    os << std::get<N-1>(t);
}
  •  

以上的程式碼, 也即通過引數傳遞的方式進行的非型別模板引數的賦值,仍然編譯不通過。非型別模板引數必須在編譯時即為常量表達式。

template<typename Tuple, size_t N>
void tuple_print(const Tuple& t, std::ostream& os)
{
    if (N != 1)
        tuple_print<Tuple, N-1>(t, os);
    os << std::get<N-1>(t);
}
  •  

這樣做似乎也編譯不通過,具體為什麼,一時也想不出來,大家有什麼思路和想法不妨提供一下。

以下是一個通行的解決方案:

template<typename Tuple, size_t N>
struct tuple_print
{
    static void print(const Tuple& t, std::ostream& os)
    {
        tuple_print<Tuple, N-1>::print(t, os);
        os << ", " << std::get<N-1>(t); 
    }
};
// 類模板的特化版本
template<typename Tuple>
struct tuple_print<Tuple, 1>
{
    static void print(const Tuple& t, std::ostream& os)
    {
        os << "(" << std::get<0>(t); 
    }
};

// operator<<
template<typename... Args>
std::ostream& operaotr<<(std::ostream& os, const std::tuple<Args...>& t)
{
    tuple_print<decltype(t), sizeof...(Args)>::print(t, os);
    return os << ")";
}
  •  

客戶端程式碼:

auto t1 = std::make_tuple("InsideZhang", 23, "HeNan");
auto t2 = std::make_tuple("InsideLi", 23, "AnHui");
// tuple_cat()   元組拼接
// 呼叫operator<< 運算子過載
std::cout << std::tuple_cat(t1, t2) << std::endl;
//  (InsideZhang, 23, HeNan, InsideLi, 23, AnHui)
  •  

因為tuple類沒有過載operator[]運算子,很難像其他容器和資料額結構一樣進行簡潔的索引動作,只能通過一個全域性的std::get<size_t>(t)進行操作。

tuple class最早公開於Boost程式庫。在那兒,tuple可以將元素寫至output stream,不知道為什麼C++標準庫不支援這一性質,而是需要我們花費一些精力手動完成這一工作。

#include <iostream>
#include <boost\tuple\tuple_io.hpp>

int main(int, char**)
{
    std::cout << boost::make_tuple("InsideZhang", 23, "HeNan") << std::endl;
    return 0;
}
  •  

References

[1]<Pretty-print std::tuple>