STL::pair

Inside_Zhang發表於2015-11-11

pair原始碼

pair類定義於通用工具<utility>標頭檔案中。STL或者更廣泛的說,C++標準庫的這種檔案組織方式,深刻地影響著軟體設計結構。簡單地說,也都有一個資料夾或者包或者模組,軟體開發過程中可能用到的工具類或者方法,統一放在這些檔案集合中。

當一個函式或者介面需要返回兩個或者更多的值時,以及在一些情況下需要成對出現一些值時,pair便會是其中的一個選擇,當然pair不限於兩個數,也可實現pair的pair,pair也是一個模板類。

pair的原始碼其實非常簡單:

// T1和T2可以是不同的型別
// T1和T2甚至都可以是pair模板
template<typename T1, typename T2>
struct pair
{
    typedef T1 first_type;
    typedef T2 second_type;
    // 為了讓程式能夠處理pair的兩個值,
    // C++標準庫使用struct進行封裝(所有成員都是public),
    // 也即提供了“直接訪問對應資料成員的能力”
    T1 first;
    T2 second;          // 兩個成員變數
    pair():first(T1()), second(T2()){}
                    // pair<T1, T2> p;
                    // default建構函式,建立一個pair,
                    // 其元素型別分別為T1和T2,
                    // 各自以其default建構函式(T1(), T2())初始化
    pair(const T1& a, const T2& b) :first(a), second(b) {}
                    // pair<T1, T2> p(val1, val2);
                    // 以val1(T1型別),val2(T2型別)為初值進行初始化
}

pair的pair

比如我們要返回一個集合的一些統計資料,如最大值、最小值以及中位數,也就是我們需要一個剛好能夠容納三個數的容器

template<typename T, typename CONT>
::pair<T, ::pair<T, T>> stats(CONT& coll)
                    // ::域作用符是為了與庫函式做區分
{
    std::sort(coll.begin(), coll.end());    
                    // 排序的目的是為了找到中位數
    auto minVal = *(coll.begin());
    auto maxVal = *(--coll.end());
    size_t  n = coll.size();
    auto median = (n%2 == 0) ? (coll[n/2] + coll[n/2-1])/2
                 : coll[n/2];
    return ::pair<T, ::pair<T, T>>(median, ::pair<T, T>(minVal, maxVal));
}

客戶端程式:

int main(int, char**)
{
    std::vector<int> ivec{0, 1, 2, 3, 4};
    auto values = stats<int, vector<int>>(ivec);
    std::cout << "min: " << values.second.first 
              << "max: " << values.second.second 
              << "median: " << values.first << std::endl; 
    return 0;
}

pair與map容器的關係

map而言,所有元素都會根據元素的鍵值自動被排序,map的所有元素都是pair,同時擁有實值(value)和鍵值(key)。pair的第一個元素(first)被視為鍵值,第二個元素被視為實值(value),map不允許兩個元素有相同的鍵值。

玩轉pair

  • 讓輸出流適配pair型別資料
template<typename T1, typename T2>
std::ostream& operator<<(std::ostream& os, const std::pair<T1, T2>& p)
{
    return os << "[" << p.first << ", " << p.second << "]" ;
}
  • 暫時忘卻模板,便捷函式std::make_pair

顯然這裡的std::make_pair是一個模板函式,如此才可使用其便捷的自動型別推導。

// 由於之前的關於輸出流的運算子過載
std::cout << std::pair<std::string, int>("InsideZhang", 23) << std::endl;

我們來看不顯式使用模板的情況:

std::cout << std::make_pair("InsideZhang", 23) << std::endl;

有了自動型別推導(無模板而無不模板)更是讓其如虎添翼:

auto p = std::make_pair("InsideZhang", 23);

根據客戶端程式,我們可輕鬆給出它的內部實現:

template<typename T1, typename T2>
std::pair<T1, T2> make_pair(const T1& x, const T2& y)
{
    return std::pair<T1, T2>(x, y);
}

再來一個自動型別推導的版本:

template<typename T1, typename T2>
auto make_pair(const T1& x, const T2& y) -> decltype(std::pair<T1, T2>(x, y))
{
    return std::pair<T1, T2>(x, y);
}

相關文章