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::cout を残しました) 私の質問は、たとえば、最後のレベルの maps_type がコンテナー型である場合、どうすれば特殊化できるのでしょうか? たとえば、 map > は技術的には 2 層構造であり、1 レベルの構造ではありません...しかし、2 つの特殊化のネストはそのタイプに対してコンパイルされません...方法に関する他の提案、おそらくこれをさらに抽象化する (理解するコンパイル時の構造の深さも) 歓迎..ありがとう!

4

3 に答える 3

4

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

まだ行っていないことは、キー値を収集して次のレベルに渡すことです。ベクトルでキーを収集してそれらを渡し続けるか、ネストの深さを把握しておおよそのタプルを使用することができます (これにより、コンパイル時間が複雑になりますn^2)。

decltypeC++03 との互換性が必要な場合は、 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;
}
于 2012-05-11T21:19:48.837 に答える
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;
  }
};
于 2012-05-12T14:43:07.110 に答える
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);
于 2012-05-12T16:17:55.700 に答える