3

私は1,2,3(最も一般的なケース)の入れ子のために、それぞれ1,2,3のループを入れ子にし、型名を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 :: coutのを取り除かここで)私の質問は、例えば、最後のレベルのmapped_typeがコンテナタイプであるときに、どのように専門化することができますか?たとえば、map>は技術的に2レベルの構造であり、1レベルの構造ではありませんが、2特殊化のネストはそのタイプではコンパイルされません...その他の方法については、コンパイル時のコンストラクトの深さも)welcomeです.thanks!

+0

缶あなたはC++ 11とvariadicテンプレートを使用しますか? – jrok

+1

途中で詰まったmapped_typesを再帰的に処理し、途中で行き止まりになり、途中でファンクタを構築する必要があります。私は何かをしようとします。 – pmr

+0

@pmrはい私は再帰的な下降を考慮していますが、座ってそれをもっと難しく考える必要があります。map >やマップ> >? –

答えて

4

これは、入れ子になっていない型が に達するまで、すべての入れ子型に対して再帰を実行します。 SFINAEを使用して、mapped_type メンバのtypedef(このようなヘルパーを作成するにはBOOST_HAS_XXXを使用できます)があるかどうかを検出します。

キー値を収集し、次のレベルに に渡すことはまだありません。ベクトル内のキーを収集し、 をそれらを渡すか、入れ子の深さを把握して、 の近似タプルを使用します(これにより、コンパイル時間の複雑さはn^2に増加します)。

C++ 03 と互換性がある場合は、decltypeとfor_eachループを使用しないでください。

#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 {dump} {dump(C const&c){dump (c) ); } ' - 元の質問が単純なフリー関数を介してファンクタを好む理由がわかりません...もう一つのニックピック:' _Up'は予約済みの識別子なので、コード内で使用しないでください。あなたが* ignored *と言うことを意図していたなら、普通の '_'を使うことができます。 –

+0

@DavidRodríguez-dribeas '_Up'は、あなたのボイラープレートSFINAEの例が' stdlib'から来たときに起こります。演繹の機能は、プロダクションに近いもので欠けてはいけません。 – pmr

+0

これは非常にクールです。私はダンプがhas_mapped_typeからの結果に基づいて適切な実装を継承していることを知っています。これについてhas_mapped_typeテストの方法について少し混乱します。 sizeof(テスト(0))は、mapped_typeへのテンプレート型ポインタを持つラップのヌルポインタを渡します...どのようにサイズを取得しますか?静的な2つのテスト(...)の目的は何ですか? –

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); 
関連する問題