I have a templatized container class in C++ which is similar to a std::map (it's basically a thread-safe wrapper around the std::map). I'd like to write a member function which dumps information about the entries in the map. Obviously, however, I don't know the type of the objects in the map or their keys. The goal is to be able to handle the basic types (integers, strings) and also some specific class types that I am particularly interested in. For any other class, I'd like to at least compile, and preferably do something somewhat intelligent, such as print the address of the object. My approach so far is similar to the following (please note, I didn't actually compile this or anything...):
template<typename Index, typename Entry>
class ThreadSafeMap
{
std::map<Index, Entry> storageMap;
...
dumpKeys()
{
for(std::map<Index, Entry>::iterator it = storageMap.begin();
it != storageMap.end();
++it)
{
std::cout << it->first << " => " << it->second << endl;
}
}
...
}
This works for basic types. I can also write custom stream insertion functions to handle specific classes I'm interested in. However, I can't figure out a good way to handle the default case where Index
and/or Entry
is an unhandled arbitrary class type. Any suggestions?
I originally had just a more canonical way of using Staffan's answer. However, jpalecek correctly pointed out a large flaw with the approach.
As it stood, if no explicit insertion operator is found, the templated insertion operator kicks in and defines a perfect match; this destroys any possibility for existing implicit conversions.
What must be done is make that template insertion operator a conversion (while maintain it's generality), so other conversions can be considered. Once no others are found, then it will be converted to the generic insertion operator.
The utility code is as such:
Stick it in some header like
"output_any.hpp"
. And you use it as such:Let me know if something doesn't make sense.
You can provide a templated
<<
operator to catch the cases where no custom output operator is defined, since any more specialized versions will be preferred over it. For example:will output:
The
detail
namespace
is there to keep this "default" output operator from interfering with code in places other than where it is needed. I.e. you should only use it (as inusing namespace detail
) in yourdumpKeys()
method.