Am struggling a lot to find how to do to use boost::any
to create a print function that can print any type using template first.
template
I do it like this, which I think is clean and safe:
any_extension.hpp:
namespace cpputil
{
struct AnyWriter
{
/// Register a type with the AnyWriter.
/// @pre T must have an ostream << operator available somewhere
template static bool registerType()
{
return registeredTypes().emplace(std::type_index(typeid(T)),
std::bind(&AnyWriter::write,
std::placeholders::_1,
std::placeholders::_2)).second;
}
/// Write any registred object to a stream
/// @pre Underlying type must have been registered with a call to AnyWriter::registerType
/// @param os is reference to a std::ostream
/// @param anyObject is a reference to a boost::any
static void writeAny(std::ostream& os, const boost::any& anyObject);
private:
// A function object that converts an any to a type and streams it to an ostream
using WriteFunction = std::function;
// a map of typeinfo to WriteFunction
using RegisteredTypes = std::unordered_map;
// retrieve the WriteFunction map in a safe way
static RegisteredTypes& registeredTypes();
// Convert an any to a type, and write it to a stream
template static void write(std::ostream& os, const boost::any& anyObject) {
try {
const T& typedObject = boost::any_cast(anyObject);
os << typedObject;
}
catch(boost::bad_any_cast& e) {
os << "";
}
}
};
}
namespace std {
ostream& operator<<(ostream& os, const ::boost::any& anyObject);
}
any_extension.cpp:
#include "any_extension.h"
#include
namespace cpputil {
namespace AnyWriterRegistration {
const bool stringRegistered = AnyWriter::registerType();
const bool intRegistered = AnyWriter::registerType();
const bool doubleRegistered = AnyWriter::registerType();
}
AnyWriter::RegisteredTypes& AnyWriter::registeredTypes()
{
static RegisteredTypes _registrationMap;
return _registrationMap;
}
void AnyWriter::writeAny(std::ostream &os, const boost::any &anyObject)
{
auto registered = registeredTypes();
auto iFind = registered.find(anyObject.type());
if(iFind == registered.end()) {
os << "";
}
else {
iFind->second(os, anyObject);
}
}
}
namespace std {
ostream& operator<<(ostream& os, const ::boost::any& anyObject)
{
if(anyObject.empty()) {
os << "";
}
else {
cpputil::AnyWriter::writeAny(os, anyObject);
}
return os;
}
}
For any type that you'd like supported, simply ensure that AnyWriter::register() has been called for its type and an operator<< exists for it.
For example:
any_test.cpp:
struct chicken {};
std::operator<<(std::ostream& os, const chicken& aChicken) {
os << "cluck!";
return os;
}
namespace {
const bool chickenRegistered = AnyWriter::register();
}
void chickenTest() {
boost::any animal = chicken();
std::cout << animal << std::endl;
}
output: cluck!