I want to make a function called debug
that outputs some info about objects. My system contains objects of many different types; some of them contain other objects.
using namespace std; // for brevity
struct dog {string name;};
struct human {string name; string address;};
struct line {list<human*> contents;};
struct pack {vector<dog*> contents;};
I want the function to output the member name
of the argument if it has one, or debug the contents
member of the argument if it has one.
I came up with the following code:
template <class T>
void debug(T object) // T here is a simple object like dog, human, etc
{
cout << object.name.c_str() << '\n';
}
// A helper function, not really important
template <class T>
void debug_pointer(T* object)
{
debug(*object);
}
void debug(pack object)
{
for_each(object.contents.begin(), object.contents.end(), debug_pointer<dog>);
}
void debug(line object)
{
for_each(object.contents.begin(), object.contents.end(), debug_pointer<human>);
}
Here, the code for pack
and line
is nearly identical! I would like to avoid writing the same code several times:
struct line {list<human*> contents; typedef human type;};
struct pack {vector<dog*> contents; typedef dog type;};
template <class T>
void debug(T object) // T here is a compound object (having contents)
{
for_each(object.contents.begin(), object.contents.end(), debug_pointer<T::type>);
}
But this syntax conflicts with the function template for the "simple" objects (has the same signature).
How can i rewrite my code? I don't want to rewrite the first part (declarations for dog
, human
, etc) because that part of my program is already very complicated, and adding stuff (base classes, member functions, etc) to it just for debugging seems out of place.
The basic code could look like this:
We need a helper class:
Now we just need a SFINAE trait class
has_name<T>
, and a mechanism to print containers. Both those problems are solved almost verbatim in the pretty printer code.