我怎样才能进一步专门化这个模板的想法呢?

时间:2012-05-11 20:25:50

标签: c++ templates boost template-specialization template-meta-programming

我认为,对于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是一个容器类型?例如,地图&gt;从技术上来说,它是一个2深度的构造,而不是一个级别的构造...但是我的2个特化的嵌套不会为该类型编译...任何其他关于如何进行的建议,或许可以进一步抽象出来(计算出深度)在编译时也是构造的)欢迎......谢谢!

3 个答案:

答案 0 :(得分:4)

这将对所有嵌套类型执行递归,直到达到a 非嵌套类型。它使用SFINAE来检测是否存在mapped_type member 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;
}

答案 1 :(得分: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;
  }
};

答案 2 :(得分: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);