
Jeffery Cavallaro schrieb:
For example, if I wanted to a program to spit out all of its options to standard out, there doesn't seem to be any hooks to extract an Any value in a generic way (e.g., as a string). Granted, I could derive a class and add methods to do so, but that doesn't work when Any is already embedded in the program_options implementation.
I made a wrapper class for boost::any (output_any) that allows to output any type that is output streamable. This method is my poor man's serialization method to convert a bunch of objects to a text representation. A full code example is below. Wouldn't it make sense to have something like output_any as a companion to boost::any in the boost distribution? Regards James BTW: If runtime performance is more important then memory, the calls to outputter_factory::get_outputter<T>() can be replaced by "new outputter<T>" #include <string> #include <iostream> #include <vector> #include <map> #include <boost/any.hpp> #include <boost/shared_ptr.hpp> #include <boost/date_time/posix_time/posix_time.hpp> using namespace boost; using namespace boost::posix_time; using namespace std; /** Interface for outputting "any" */ struct base_out { typedef shared_ptr<base_out> ptr; virtual void output(ostream &o, const any &a) const = 0; }; /** Concrete outputter for "any" of type T */ template<typename T> struct outputter : public base_out { void output(ostream &o, const any &a) const { const T& c = any_cast<T>(a); o << c; } }; /** Creates outputter instances for different types. */ class outputter_factory { public: /** Returns an outputter for type T - not threadsafe! * @throws bad_allow if the new outputter * cannot be inserted into the map. */ template<typename T> static base_out::ptr get_outputter() { const char * type_name = typeid(T).name(); ptr_map::const_iterator f = ptrs_.find(type_name); if (f == ptrs_.end()) { pair<ptr_map::iterator, bool> ret = ptrs_.insert(make_pair(type_name, base_out::ptr(new outputter<T>))); if (!ret.second) { throw bad_alloc("Could not insert new outputter into map"); } f = ret.first; } return f->second; } private: typedef map<const char*, base_out::ptr> ptr_map; static ptr_map ptrs_; }; outputter_factory::ptr_map outputter_factory::ptrs_; /** Allows to output just "any"thing. Inspired by the class any_out * in the book "Beyond the C++ Standard Library" */ class output_any { public: /** Default c'tor */ output_any() {} /** Construction from any object of type T */ template<typename T> output_any(const T &a) : outputter_(outputter_factory::get_outputter<T>()), a_(a) {} /** Copy c'tor */ output_any(const output_any &other) : outputter_(other.outputter_), a_(other.a_) {} /** Assignment from other output_any */ output_any& operator=(output_any& r) { outputter_ = r.outputter_; a_ = r.a_; return *this; } /** Assignment from any instance of type T */ template<typename T> output_any& operator=(const T& t) { outputter_ = outputter_factory::get_outputter<T>(); a_ = any(t); return *this; } /** Safely swaps *this with other */ output_any &swap(output_any &other) { a_.swap(other.a_); outputter_.swap(other.outputter_); return *this; } /** Give the ostream operator acces to * our private methods and vars. */ friend ostream & operator<<(ostream &o, const output_any &a); private: /** Outputs a_ */ void output(ostream &o) const { if (outputter_) { outputter_->output(o, a_); } } base_out::ptr outputter_; any a_; }; /** Output an output_any */ ostream & operator<<(ostream &o, const output_any &a) { a.output(o); return o; } /** Prints all elements of the container c line by line * to cout */ template<typename Container> void output_all(const Container &c) { for(Container::const_iterator i = c.begin(); i != c.end(); ++i) { cout << *i << endl; } } /** Some dummy class to show that ouput_any can * output - well - any type that defines and output * operator. */ class my_type { public: my_type(int a, int b) : a_(a), b_(b) {} friend ostream & operator<<(ostream &o, const my_type &m); private: int a_, b_; }; /** Output my_type */ ostream & operator<<(ostream &o, const my_type &m) { o << "a is " << m.a_ << " and b is " << m.b_; return o; } int main() { output_any o1(10); output_any o2(3.1415); output_any o3(string("foo")); output_any o4; o4 = o3; o4 = string("gugus"); output_any o5; o5 = my_type(33, 44); o1.swap(o3); cout << o1 << endl; cout << o2 << endl; cout << o3 << endl; cout << o4 << endl; cout << o5 << endl; // Put some output_any instance into a vector // and output all of them... vector<output_any> some_values; some_values.push_back(output_any(string("bar"))); some_values.push_back(output_any(1500)); some_values.push_back(output_any(34)); some_values.push_back(output_any(193)); some_values.push_back(output_any(1.2345)); some_values.push_back(output_any(my_type(10, 30))); some_values.push_back(output_any(second_clock::local_time())); cout << endl << "The values from the container:" << endl; output_all(some_values); string in; getline(cin, in); return 0; }