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 以简化此处的示例代码)我的问题是,当最后一级 mapped_type 是容器类型时,我该如何进行专业化?例如 map > 在技术上是一个 2-depth 构造,而不是一个单级构造...但是我的 2 个专业化嵌套不会为该类型编译...任何其他关于如何的建议,也许进一步抽象 thsi(弄清楚欢迎在编译时构造的深度)..谢谢!

4

3 回答 3

4

这将对所有嵌套类型执行递归,直到它到达非嵌套类型。它使用 SFINAE 来检测是否存在mapped_type 成员 typedef(您可以使用它BOOST_HAS_XXX来创建这样的助手)。

它还没有做的是收集键值并将它们传递到下一个级别。您可以收集向量中的键并继续向下传递它们,或者计算嵌套深度并使用近似元组(这会将编译时间复杂度增加到n^2)。

decltype如果您希望与 C++03 兼容,请不要使用and 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 回答