$include_dir="/home/hyper-archives/boost-users/include"; include("$include_dir/msg-header.inc") ?>
From: Jean-Pierre Bergamin (james_at_[hidden])
Date: 2008-04-24 17:59:49
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;
}