3

我可以用模板專門化來做到這一點,我認爲,嵌套1,2,3(最常見的情況下)通過分別嵌套1,2,3 for循環和引用類型的他們的類型名稱在stl ...但對於任意深度,不使用預處理器,有沒有辦法做到這一點?也許用mpl?或者我還需要預處理器工具嗎?現在我做這樣的事情:我怎樣才能進一步專注於這個模板的想法?

template<typename T, int> 
struct MapDump {}; 

template<typename T > 
struct MapDump<T,1> 
{ 
    static void dump(const T& map, string file, string header="") 
    { 
    if (!header.empty()) 
     cout << header << endl; 

    for (typename T::const_iterator cIt = map.begin(); 
     cIt != map.end(); 
     ++cIt) 
     cout << cIt->first << "," << cIt->second << endl; 
    } 
}; 

template<typename T > 
struct MapDump<T,2> 
{ 
    static void dump(const T& map, string file, string header="") 
    { 
    if (!header.empty()) 
     cout << header << endl; 

    for (typename T::const_iterator it1 = map.begin(); 
     it1 != map.end(); 
     ++it1) 
     for (typename T::mapped_type::const_iterator it2 = it1->second.begin(); 
      it2 != it1->second.end(); 
      ++it2) 
     cout << it1->first << "," << it2->first << "," << it2->second << endl; 
    } 
}; 

,我可以用打電話,例如:

map<int, map<int, double> > m; 
    m[1][1] = 1.0; 
    m[1][2] = 1.0; 
    m[2][1] = 2.0; 
    m[2][2] = 2.0; 

    MapDump< map<int, map<int, double> >, 2 >::dump(m, "test.csv"); 

(我剝出fstream的東西,左的std ::法院,以簡化示例代碼在這裏)我的問題是,當我說最後一層mapped_type是一個容器類型時,我該如何去專門研究?例如,map>在技術上是一個2深度的構造,而不是一個一級的構造......但是我的2個專業化的嵌套不能編譯爲這種類型......關於如何進一步抽象的任何其他建議(弄清楚編譯時的構造深度也是如此),謝謝!

+0

燦你使用C++ 11和variadic模板? – jrok

+1

您需要對嵌套的mapped_types進行遞歸處理,直到您到達死路一條,並沿途建立仿函數。我會盡力去做一些事情。 – pmr

+0

@pmr是的,我雖然是遞歸下行遍歷,但我不得不坐下來思考它,如何像地圖>或地圖> >? –

回答

4

這會對所有嵌套類型執行遞歸,直到達到非嵌套類型的 。它使用SFINAE來檢測是否存在mapped_type 成員typedef(您可以使用BOOST_HAS_XXX來創建這樣一個幫助器)。

它還沒有做的是收集關鍵值並將它們傳遞到 到一個新的水平。您可以收集向量中的密鑰並保持 將它們向下傳遞或找出嵌套深度,並使用近似元組(這會增加編譯時間複雜度至n^2)。

不要使用decltype和for_each循環,如果你想要兼容C++ 03 。

#include <map> 
#include <iostream> 

// sfinae to detect a mapped type 
template<typename T> 
struct has_mapped_type 
{ 
private: 
    typedef char one; 
    typedef struct { char arr[2]; } two; 
    template<typename U> 
    struct wrap {}; 

    template<typename U> 
    static one test(wrap<typename U::mapped_type>*); 

    template<typename U> 
    static two test(...); 
public: 
    static const bool value = sizeof(test<T>(0)) == 1; 
}; 


template<typename T, bool has_mapped_type> 
// false version 
struct dump_impl { 
    void operator()(const T& t) const { 
    std::cout << t << std::endl; 
    } 
}; 

template<typename T> 
// true version 
struct dump_impl<T, true> 
    : dump_impl< 
    typename T::mapped_type 
    , has_mapped_type<typename T::mapped_type>::value 
    > 
{ 
    void operator()(const T& t) const { 
    for(auto& x : t) { 
     dump_impl< 
     typename T::mapped_type 
     , has_mapped_type<typename T::mapped_type>::value 
     >:: 
     operator()(x.second); 
    } 
    } 
}; 

template<typename T> 
struct dump : public dump_impl<T, has_mapped_type<T>::value> { 
    void operator()(const T& t) const { 
    dump_impl<T, has_mapped_type<T>::value>::operator()(t); 
    } 
}; 

int main() 
{ 
    std::map<int, std::map<int, double> > m; 
    m[1][1] = 1.0; 
    m[1][2] = 1.0; 
    m[2][1] = 2.0; 
    m[2][2] = 2.0; 

    dump<decltype(m)>()(m); 
    return 0; 
} 
+0

小評論(我甚至沒有讀過代碼:),你可以通過讓編譯器通過函數推斷出類型來避免用戶的一些複雜性:'template dump_map(C const&c){dump ()(c ); }' - 我不確定爲什麼原始問題比普通的自由函數更喜歡一個函子......另一個挑剔:'_Up'是一個保留的標識符,你不應該在你的代碼中使用它。如果你打算說*忽略*,你可以使用普通的'_'。 –

+0

@DavidRodríguez-dribeas'_Up'發生在您的樣板SFINAE示例來自'stdlib'時。在任何接近生產的情況下,推演功能都不應該缺失。 – pmr

+0

這很酷。我看到該轉儲基於來自has_mapped_type的結果繼承了適當的實現。我對has_mapped_type如何測試這個有點困惑。 sizeof(測試(0))傳遞一個包含模板類型指針的空指針到mapped_type ...如何檢索大小?靜態兩個測試(...)的目的是什麼? –

1

嘗試

template<int I> 
struct Int { }; 

template<typename T, int I> 
struct MapDump 
{ 
    static void dump(const T& map, const string& file, const string& header="") { 
    if (!header.empty()) 
     cout << header << endl; 
    dump(map, "", Int<I>()); 
    } 

private: 
    template<typename Map, int I1> 
    static void dump(const Map& map, const string& agg, Int<I1>) { 
    for (typename Map::const_iterator cIt = map.begin(); 
     cIt != map.end(); 
     ++cIt) { 
     dump(cIt->second, (agg + boost::lexical_cast<std::string>(
     cIt->first) + ", "), Int<I1-1>()); 
    } 
    } 

    template<typename D> 
    static void dump(const D& d, const string& agg, Int<0>) { 
    cout << agg << d << endl; 
    } 
}; 
0

下面是一個簡單的遞歸函數模板,將打印嵌套地圖:

template <typename Last> 
void dumpMap(const Last &last,const std::string &first) 
{ 
    std::cout << first << last << "\n"; 
} 

template <typename A,typename B> 
void dumpMap(const std::map<A,B> &last,const std::string &first=std::string()) 
{ 
    typename std::map<A,B>::const_iterator i=last.begin(), i_end=last.end(); 
    for (;i!=i_end;++i) { 
    std::ostringstream s; 
    s << first << (*i).first << ","; 
    dumpMap((*i).second,s.str()); 
    } 
} 

您可以使用它像這樣:

map<int, map<int, double> > m; 
m[1][1] = 1.0; 
m[1][2] = 1.0; 
m[2][1] = 2.0; 
m[2][2] = 2.0; 

dumpMap(m);