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
#include
#include
using namespace boost;
using namespace boost::posix_time;
using namespace std;
/** Interface for outputting "any"
*/
struct base_out {
typedef shared_ptr 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 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 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 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;
}