blob: fbf07ddb8ee3c10c97e1a3e46b11fdf0b8333cb7 [file] [log] [blame]
// 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