Boost logo

Boost Users :

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;
}


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net