| // 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 |