开发者

How to dump nested maps in C++ for debugging purposes?

for debugging I need to dump the contents of nested maps. I tried to describe this in the following code:

struct Foo
{       
   string name;
};

typedef std::map<string, Foo> MapFoo;

struct Bar  {
  string name;    
  MapFoo mapFoo;
};

typedef std::map<string, Bar> MapBar;

...

MapBar开发者_Go百科 mapBar = init_mapBar(); 

const MapBar::const_iterator it = mapBar.find("name");

if ( mapBar.end() != it )
{
    return it->second;
}

Before I return it->second, I want to dump the contents of that item to cout. I am getting lost with the iterators when trying doing this. Thank you very much for some help or hints.


you can use two separate. One for a map <string, int> and one for a map<string, map<string, int> >.

For Example, something like:
Note: I haven't tested the code.

map <string, map <string, int> > foo;
// fill map
map <string, map <string, int> >::iterator outerit;

map <string, int>::iterator innerit;

for (outerit = foo.begin(); outerit != foo.end(); ++outerit)
{
    for (innerit = outerit->second.begin(); innerit != outerit->second.end();++innerit)
    {
        cout << outerit->first << " " <<  innerit->first << " " << innerit->second << "\n";
        //Write contents to a file here
    }
}


Write a function:

template <typename K, typename V, typename C>
void Dump( const map <K,V,C> & m ) {
    typename map <K,V,C>::const_iterator it = m.begin();
    while( it != m.end() ) {
        cout << it->first << " = " << it->second << endl;
        ++it;
    }
}

You can then say:

if ( mapBar.end() != it )
{
    Dump( it->second );
    return it->second;
}

and use it for dumping any other maps where K & V are types that have streaming operators available.


You can add this before the return statement

std::cout << "name: " << it->second.name << std::endl;
MapFoo::const_iterator it2;
for (it2 = it->second.mapFoo.begin(); it2 != it->second.mapFoo.end(); ++it2)
  std::cout << it2->second.name << std::endl


If you want to avoid any coding at all and just need a quick-and-cheap solution, you can use our magic container printer -- just include the header and bingo. (If you're not in C++0x, you may have to remove the tuple stuff and put a space between angled brackets.)


I tend to prefer operator overloading. It works really well coupled with some "decorators".

First a range adapter, that we'll use for any container

template <typename It>
struct Range
{
  Range(It b, It e): begin(b), end(e) {}
  It begin; It end;
};

template <typename It>
Range<It> MakeRange(It b, It e) { return Range<It>(b,e); }

template <typename C>
Range<typename C::const_iterator> MakeRange(C const& c) {
  return Range<typename C::const_iterator>(c.cbegin(), c.cend());
}

template <typename Stream, typename It>
Stream& operator<<(Stream& out, Range<It> range) {
  if (range.begin == range.end) { return out; }

  out << *range.begin;
  for (++range.begin; range.begin != range.end; ++range.begin) {
    out << *range.begin;
  }
  return out;
}

Next a Decorator for pairs printing (either tuple-mode or dictionary mode):

template <typename Stream>
class StreamPairDict
{
public:
  StreamPairDict(Stream& b): base(b) {}

  template <typename T, typename U>
  StreamPairDict& append(std::pair<T,U> const& p) {
    base << p.first << ": " << p.second;
    return *this;
  }

  template <typename Other>
  StreamPairDict& append(Other const& o) {
    base << o; return *this;
  }

private:
  Stream& base;
};

template <typename S, typename T>
StreamPairDict<S>& operator<<(StreamPairDict<S>& stream, T const& t) {
  return s.append(t);
}

template <typename S, typename Stream>
StreamPairDict<S> MakeStreamPairDict(Stream& s) {
  return StreamPairDict<S>(s);
}

And finally, a general decorator, to trigger ADL without invading the std namespace:

template <typename S>
class Stream
{
public:
  typedef S Base;

  Stream(Base& b): base(b) {}

  template <typename T>
  Stream& append(T const& t) { base << t; return *this; }

private:
  Base& base;
};

template <typename S>
Stream<S>& operator<<(Stream<S>& s, bool b) { return s.append(b); }

template <typename S, typename Num>
typename std::enable_if< std::is_arithmetic<Num>::value, Stream<S>&>::type
operator<<(Stream<S>& s, Num n) { return s.append(n); }

template <typename S>
Stream<S>& operator<<(Stream<S>& s, char const* string) {
  return s.append(string);
}

template <typename S>
Stream<S>& operator<<(Stream<S>& s, std::string const& string) {
  return s.append(string);
}

/// many containers in the STL !!!
template <typename S, typename K, typename V, typename L, typename A>
Stream<S>& operator<<(Stream<S>& s, std::map<K,V,L,A> const& map) {
  return MakeStreamPairDict(s) << '{' << MakeRange(map) << '}';
}

template <typename S, typename K, typename V, typename L, typename A>
Stream<S>& operator<<(Stream<S>& s, std::multimap<K,V,L,A> const& map) {
  return MakeStreamPairDict(s) << '{' << MakeRange(map) << '}';
}

template <typename S, typename K, typename V, typename H, typename A>
Stream<S>& operator<<(Stream<S>& s, std::unordered_map<K,V,H,A> const& map) {
  return MakeStreamPairDict(s) << '{' << MakeRange(map) << '}';
}

template <typename S, typename K, typename V, typename H, typename A>
Stream<S>& operator<<(Stream<S>& s, std::unordered_multimap<K,V,H,A> const& map) {
  return MakeStreamPairDict(s) << '{' << MakeRange(map) << '}';
}

And it's used easily:

int main() {
  std::map<int, std::map<char, Custom> > myMap;
  Stream(std::cout) << myMap << '\n';
}

will work if there is a std::ostream& operator<<(std::ostream&, Custom const&).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜