diff options
Diffstat (limited to 'boost/python/pure_virtual.hpp')
-rw-r--r-- | boost/python/pure_virtual.hpp | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/boost/python/pure_virtual.hpp b/boost/python/pure_virtual.hpp new file mode 100644 index 0000000000..b3b34ffcdb --- /dev/null +++ b/boost/python/pure_virtual.hpp @@ -0,0 +1,124 @@ +// Copyright David Abrahams 2003. +// 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) +#ifndef PURE_VIRTUAL_DWA2003810_HPP +# define PURE_VIRTUAL_DWA2003810_HPP + +# include <boost/python/def_visitor.hpp> +# include <boost/python/default_call_policies.hpp> +# include <boost/mpl/push_front.hpp> +# include <boost/mpl/pop_front.hpp> + +# include <boost/python/detail/nullary_function_adaptor.hpp> + +namespace boost { namespace python { + +namespace detail +{ + // + // @group Helpers for pure_virtual_visitor. { + // + + // Raises a Python RuntimeError reporting that a pure virtual + // function was called. + void BOOST_PYTHON_DECL pure_virtual_called(); + + // Replace the two front elements of S with T1 and T2 + template <class S, class T1, class T2> + struct replace_front2 + { + // Metafunction forwarding seemed to confound vc6 + typedef typename mpl::push_front< + typename mpl::push_front< + typename mpl::pop_front< + typename mpl::pop_front< + S + >::type + >::type + , T2 + >::type + , T1 + >::type type; + }; + + // Given an MPL sequence representing a member function [object] + // signature, returns a new MPL sequence whose return type is + // replaced by void, and whose first argument is replaced by C&. + template <class C, class S> + typename replace_front2<S,void,C&>::type + error_signature(S BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(C)) + { + typedef typename replace_front2<S,void,C&>::type r; + return r(); + } + + // + // } + // + + // + // A def_visitor which defines a method as usual, then adds a + // corresponding function which raises a "pure virtual called" + // exception unless it's been overridden. + // + template <class PointerToMemberFunction> + struct pure_virtual_visitor + : def_visitor<pure_virtual_visitor<PointerToMemberFunction> > + { + pure_virtual_visitor(PointerToMemberFunction pmf) + : m_pmf(pmf) + {} + + private: + friend class python::def_visitor_access; + + template <class C_, class Options> + void visit(C_& c, char const* name, Options& options) const + { + // This should probably be a nicer error message + BOOST_STATIC_ASSERT(!Options::has_default_implementation); + + // Add the virtual function dispatcher + c.def( + name + , m_pmf + , options.doc() + , options.keywords() + , options.policies() + ); + + typedef BOOST_DEDUCED_TYPENAME C_::metadata::held_type held_type; + + // Add the default implementation which raises the exception + c.def( + name + , make_function( + detail::nullary_function_adaptor<void(*)()>(pure_virtual_called) + , default_call_policies() + , detail::error_signature<held_type>(detail::get_signature(m_pmf)) + ) + ); + } + + private: // data members + PointerToMemberFunction m_pmf; + }; +} + +// +// Passed a pointer to member function, generates a def_visitor which +// creates a method that only dispatches to Python if the function has +// been overridden, either in C++ or in Python, raising a "pure +// virtual called" exception otherwise. +// +template <class PointerToMemberFunction> +detail::pure_virtual_visitor<PointerToMemberFunction> +pure_virtual(PointerToMemberFunction pmf) +{ + return detail::pure_virtual_visitor<PointerToMemberFunction>(pmf); +} + +}} // namespace boost::python + +#endif // PURE_VIRTUAL_DWA2003810_HPP |