|
Boost : |
From: Christian Holmquist (c.holmquist_at_[hidden])
Date: 2007-09-07 10:00:28
Hello all,
Is there any visitor mechanism somewhere in boost that allows one to
introspect the contained type of a boost::any?
I've been using boost::variant frequently and I love the way its visitor
works, but it's not always practical to know all possible types at compile
time (library dependencies, compilation time etc..).
I thought something similiar for boost::any, and I put together a small
test:
any_variant<T0, T1, T2> any_of_type_T0_T1_T2;
It allows visitation of the types given as template parameters. A trivial
example would be
struct print_visitor
{
template<class T>
void operator()(const T& x) const
{
std::cout << x <<std::endl;
}
};
void test()
{
typedef any_variant<int, float, std::string> any_types;
boost::any a;
any_types v(a);
a = (int) 35;
v(print_visitor());
a = std::string("str");
v(print_visitor());
a = (double) 45.0;
v(print_visitor());
}
// prints
35
str
Also the example from boost::any docs,
class consumer
{
public:
virtual void notify(const any &) = 0;
...
};
could be implemented like
class my_consumer : public consumer
{
virtual void notify(const any &a)
{
any_variant<msg0, msg1> av(a);
av(*this);
}
void operator()(const msg0&);
void operator()(const msg1&);
}
The implementation is very basic, it just iterates over the types and
compares typeids. If a match is found it calls the visitor and returns true,
otherwise false.
Does anyone else have a use for this, or have another solution at hand?
Best regards,
Christian
#include <boost/any.hpp>
#include <boost/mpl/begin.hpp>
#include <boost/mpl/end.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/control/expr_if.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
namespace detail
{
template<bool done = true>
struct typeitr_loop
{
template<typename Iterator, typename LastIterator, typename Visitor>
static bool invoke(boost::any&, Visitor)
{
return false;
}
};
template<>
struct typeitr_loop<false>
{
template<typename Iterator, typename Last, typename Visitor>
static bool invoke(boost::any& a, Visitor v)
{
typedef boost::mpl::deref<Iterator>::type type;
if(typeid(type) == a.type())
{
v(*boost::unsafe_any_cast<type>(&a));
return true;
}
else
{
typedef boost::mpl::next<Iterator>::type itr;
return typeitr_loop<boost::is_same<itr,
Last>::value>::invoke
<itr, Last>(a, v);
}
}
};
template<class Types, class Visitor> inline
bool visit_any_type(boost::any& a, Visitor f)
{
typedef typename boost::mpl::begin<Types>::type first;
typedef typename boost::mpl::end<Types>::type last;
return detail::typeitr_loop<boost::is_same<first,
last>::value>::invoke
<first, last>(a, f);
}
}
//
// Preprocessor code copied from <boost/multi_index/indexed_by.hpp>
//
#ifndef ANY_VISITOR_LIMIT_TYPES
#define ANY_VISITOR_LIMIT_TYPES 10
#endif
#define ANY_VISITOR_TEMPLATE_PARM(z,n,var) \
typename BOOST_PP_CAT(var,n) BOOST_PP_EXPR_IF(n,=boost::mpl::na)
template
<
BOOST_PP_ENUM(
ANY_VISITOR_LIMIT_TYPES,
ANY_VISITOR_TEMPLATE_PARM,T)
>
class any_variant
{
boost::any& any_;
public:
typedef
boost::mpl::vector<BOOST_PP_ENUM_PARAMS(ANY_VISITOR_LIMIT_TYPES,T)> types;
any_variant(boost::any& a) : any_(a) {}
typedef bool result_type;
template<class Visitor>
bool operator()(Visitor v) const
{
return detail::visit_any_type<types>(any_, v);
}
};
#undef ANY_VISITOR_TEMPLATE_PARM
#undef ANY_VISITOR_LIMIT_TYPES
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk