1. 程式人生 > >c++11模板:容器(map,set,list,vector)中元素型別轉換

c++11模板:容器(map,set,list,vector)中元素型別轉換

簡單的資料型別轉換很簡單,比如下面cast模板函式族:

// 相同型別直接轉發
template<typename L>
L
cast(L left, typename std::decay<L>::type *) {
    return std::forward<L>(left);
}
// 不同算術(數字)型別之間強制轉換
template<typename L, typename R>
typename std::enable_if<std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,R>::type
cast(L left,R*right) {
    return
(R)left; } // 列舉型別強制轉換 template<typename L, typename R> typename std::enable_if<std::is_enum<L>::value && std::is_enum<R>::value, R>::type cast(L left, R*right) { return (R)left; } // 數字轉字串 template<typename L> typename std::enable_if<std::is_arithmetic<L>::value, std
::string>::type cast(L left,std::string *right) { std::ostringstream ss; ss << left; return ss.str(); } // 字串轉數字 template<typename R> typename std::enable_if<std::is_arithmetic<R>::value, R>::type cast(const std::string &left, R *) { std::istringstream ss(left); R right; ss >> right; return
right; }

那麼對於容器型別,有沒有方便簡單的辦法呢?
c++11 <algorithm>庫中的std::transform函式就可以很方便的實現容器中元素型別的轉換,比如list

template<
    typename L, // 源型別
    typename R  // 目標型別
    >
std::list<R>cast(const std::list<L>&left, std::list<R>*) {
    std::list<R> right;
    std::transform(
        left.begin(), // 輸入容器迭代器(開始)
        left.end(), // 輸入容器迭代器(結尾)
        std::insert_iterator<std::list<R>>(right, right.begin()), // 輸出迭代器
        [](L l)->R {return cast(l, (R*)nullptr); } // lambda表示式呼叫上面的定義的Cast函式完成元素型別轉換
        // 如果上面的cast函式無法滿足要求,請自行根據需要擴充套件。
    );
    return std::move(right);
}

對於std::set,std::vector也是一樣的邏輯,只是把set換成setvector
對於std::map,邏輯是一樣的,但std::map有K,V兩個資料型別,所以程式碼上稍有不同:

template<
    typename KL, // Key源型別
    typename VL, // Value源型別
    typename KR, // Key目標型別
    typename VR> // Value目標型別
std::map<KR, VR>cast(const std::map<KL, VL>&left, std::map<KR, VR>*) {
    std::map<KR, VR> right;
    std::transform(
        left.begin(), // 輸入entry迭代器開始
        left.end(), // 輸入entry迭代器結尾
        std::insert_iterator<std::map<KR, VR>>(right, right.begin()), // 輸出迭代器
        [](std::pair<KL, VL> l)->std::pair<KR, VR> {
            // 修改每個entry的key和value型別返回回新的鍵值對
            return std::pair<KR, VR>(cast(l.first, (KR*)nullptr), cast(l.second, (VR*)nullptr)); 
        }
    );
    return std::move(right);
}

呼叫示例

#include <algorithm>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <sstream>
#include <type_traits>
#include <string>
int main(int argc, char *argv[]) {
    // list呼叫示例
    std::list<int> intlist{ 1,2,3,4,5 };
    auto strlist2 = cast(intlist, (std::list<std::string>*)nullptr);
    for (auto e : strlist2) {
        std::cout << e << std::endl;
    }
    // map 呼叫示例
    std::map<std::string, int> map1;
    map1["88"] = 69;
    map1["99"] = 199;
    map1["100"] = 50;
    // 轉換value型別 int->std::string
    auto map2 = cast(map1, (std::map<std::string,std::string>*)nullptr);
    std::cout << "map2 = "; print_map(map2);
    // 轉換key,value型別 
    // std::string->int
    // int -> std::string
    auto map3 = cast(map1, (std::map<int,std::string>*)nullptr);
    std::cout << "map3 = "; print_map(map3);
}