применив немножко MPL, получил следующее:
#include <boost/mpl/vector.hpp>
#include <boost/mpl/find.hpp>
#include <boost/mpl/distance.hpp>
#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/size.hpp>
struct visitor
{
typedef boost::mpl::vector<
some,
other
>::type types;
template<class Impl>
visitor(Impl* impl) : impl(impl), onVisit(&ImplWrap<Impl>::on_visit) {}
template<typename T>
void visit(T& obj)
{
typedef typename boost::mpl::find<types, T>::type iter;
const int idx = boost::mpl::distance<boost::mpl::begin<types>::type, iter>::type::value; //iter::pos::value; ???
onVisit(impl, obj, idx);
}
template<class Impl>
struct ImplWrap
{
typedef void (*call_visit_fn_t)(Impl& impl, node& el);
template<int idx>
static void call_visit(Impl& impl, node& obj)
{
impl(static_cast<boost::mpl::at_c<types, idx>::type&>(obj));
}
template<int idx>
static bool fill_item(call_visit_fn_t* table)
{
table[idx - 1] = &call_visit<idx - 1>;
return fill_item<idx - 1>(table);
}
template<>
static bool fill_item<0>(call_visit_fn_t*)
{
return 0;
}
static void on_visit(void* impl, node& obj, int typeIdx)
{
static const size_t tableSize = boost::mpl::size<types>::value;
static call_visit_fn_t table[tableSize];
static bool tableInitialized = fill_item<tableSize>(table);
table[typeIdx](*(Impl*)impl, obj);
}
};
void* impl;
void (*onVisit)(void* impl, node& obj, int typeIdx);
};
template<class Vis>
inline void apply_visitor(Vis& vis, node* n)
{
visitor impl(&vis);
n->accept(&impl);
}
gcc это компилить отказывается (и за специализации fill_item внутри класса) (тот который на codepad.org), а MSVC2010 компилит нормально
выглядит это страшно, хоть и без макросов, но всёравно страшно.
может можно как-то упростить, с тем же С++0х (которое есть в MSVC)