Boost logo

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