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&)
.
精彩评论