// dispatch.cpp // // Copyright (c) 2010 // Steven Watanabe // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // implements a dynamic dispatcher for boost::any. #include #include #include #include #include #include #include #include #include // A POD pair used in the static table. It needs to // have a trivial constructor. The actual initialization // will be handled by boost::call_once template struct type_pair { const std::type_info* first; T second; }; // comparison operator used to sort the table, // so that we can do a binary search instead // of a linear search. template bool operator<(const type_pair& lhs, const type_pair& rhs) { return lhs.first->before(*rhs.first) != false; } // dummy template needed for mpl::for_each template struct wrap {}; // trampoline function that forwards the overload of // f for a specific type. template typename F::result_type dispatch_func(F& f, T& t) { using boost::any_cast; return f(any_cast(t)); } // exception thrown if we're passed a type that // we don't know what to do with. struct bad_function_call : std::runtime_error { bad_function_call() : std::runtime_error("bad_function_call") {} }; // a function object that dispatches // an any that holds one of a fixed set of types. template class static_dispatcher { public: typedef typename F::result_type result_type; static_dispatcher(const F& f) : f(f) { boost::once_flag flag = BOOST_ONCE_INIT; boost::call_once(flag, &do_init); } typename F::result_type operator()(T& t) { element_type element = { &t.type(), 0 }; typename table_type::iterator pos = std::lower_bound(table.begin(), table.end(), element); if(pos == table.end()) { throw bad_function_call(); } else { return pos->second(f, t); } } private: typedef typename F::result_type (*function_type)(F&, T&); typedef type_pair element_type; typedef boost::array::value> table_type; static table_type table; struct initializer { template void operator()(const wrap&) { element_type result = { &typeid(T1), static_cast(&dispatch_func) }; *(*current)++ = result; } element_type** current; }; static void do_init() { element_type* current = &table[0]; initializer init = { ¤t }; boost::mpl::for_each >(init); std::sort(table.begin(), table.end()); } F f; }; template typename static_dispatcher::table_type static_dispatcher::table; // Now let's have a simple function object. struct print { typedef void result_type; template void operator()(const T& t) const { std::cout << t << std::endl; } }; int main() { static_dispatcher, print, boost::any> f = print(); boost::any a = 1; f(a); a = 2.5; f(a); a = 'a'; f(a); }