2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-24 06:02:14 +00:00

Implemented pure_virtual(...)

[SVN r19774]
This commit is contained in:
Dave Abrahams
2003-08-25 18:44:26 +00:00
parent 87c5e37f5e
commit 7ec78eecbd
5 changed files with 221 additions and 4 deletions

View File

@@ -0,0 +1,41 @@
// Copyright David Abrahams 2003. Permission to copy, use,
// modify, sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
#ifndef NULLARY_FUNCTION_ADAPTOR_DWA2003824_HPP
# define NULLARY_FUNCTION_ADAPTOR_DWA2003824_HPP
namespace boost { namespace python { namespace detail {
// nullary_function_adaptor -- a class template which ignores its
// arguments and calls a nullary function instead. Used for building
// error-reporting functions, c.f. pure_virtual
template <class NullaryFunction>
struct nullary_function_adaptor
{
nullary_function_adaptor(NullaryFunction fn)
: m_fn(fn)
{}
void operator()() const { m_fn(); }
# define BOOST_PP_LOCAL_MACRO(i) \
template <BOOST_PP_ENUM_PARAMS_Z(1, i, class A)> \
void operator()( \
BOOST_PP_ENUM_BINARY_PARAMS_Z(1, i, A, const& BOOST_PP_INTERCEPT) \
) const \
{ \
m_fn(); \
}
# define BOOST_PP_LOCAL_LIMITS (1, BOOST_PYTHON_MAX_ARITY)
# include BOOST_PP_LOCAL_ITERATE()
private:
NullaryFunction m_fn;
};
}}} // namespace boost::python::detail
#endif // NULLARY_FUNCTION_ADAPTOR_DWA2003824_HPP

View File

@@ -0,0 +1,127 @@
// Copyright David Abrahams 2003. Permission to copy, use,
// modify, sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
#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/python/arg_from_python.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
{
//
// { Helpers for pure_virtual_visitor, below.
//
// 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 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();
}
//
// } Helpers for pure_virtual_visitor
//
//
// 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 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_::select_holder::held_type held_t;
// Add the default implementation which raises the exception
c.def(
name
, detail::make_function_aux(
detail::nullary_function_adaptor<void(*)()>(pure_virtual_called)
, default_call_policies()
, args_from_python()
, detail::error_signature<held_t>(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

View File

@@ -627,7 +627,7 @@ handle<> function_handle_impl(py_function const& f)
new function(f, 0, 0)));
}
}
} // namespace objects
namespace detail
{
@@ -639,6 +639,11 @@ namespace detail
f
, keyword_range(&k,&k));
}
void BOOST_PYTHON_DECL pure_virtual_called()
{
PyErr_SetString(PyExc_RuntimeError, "Pure virtual function called");
throw_error_already_set();
}
}
}} // namespace boost::python::objects
}} // namespace boost::python

View File

@@ -9,6 +9,7 @@
#include <boost/python/manage_new_object.hpp>
#include <boost/python/reference_existing_object.hpp>
#include <boost/python/call_method.hpp>
#include <boost/python/pure_virtual.hpp>
#include <boost/python/def.hpp>
#include <boost/utility.hpp>
@@ -20,6 +21,27 @@ struct Callback
PyObject* mSelf;
};
struct P
{
virtual ~P(){}
virtual std::string f() = 0;
};
struct PCallback : P, Callback
{
PCallback (PyObject* self) : Callback(self) {}
std::string f()
{
return call_method<std::string>(mSelf, "f");
}
};
struct Q : P
{
std::string f() { return "Q::f()"; }
};
struct A
{
virtual ~A(){}
@@ -44,7 +66,7 @@ struct ACallback : A, Callback
struct B : A
{
virtual std::string f() { return "B::f()"; }
virtual std::string f() { return "B::f()"; }
};
struct C : A
@@ -127,6 +149,13 @@ BOOST_PYTHON_MODULE_INIT(polymorphism_ext)
def("factory", factory, return_value_policy<manage_new_object>());
def("call_f", call_f);
class_<P,boost::noncopyable,PCallback>("P")
.def("f", pure_virtual(&P::f))
;
class_<Q, bases<P> >("Q")
;
}
//#include "module_tail.cpp"

View File

@@ -46,7 +46,22 @@ class PolymorphTest(unittest.TestCase):
def test_wrapper_downcast(self):
a = pass_a(D())
self.failUnlessEqual('D::g()', a.g())
def test_pure_virtual(self):
p = P()
self.assertRaises(RuntimeError, p.f)
q = Q()
self.failUnlessEqual ('Q::f()', q.f())
class R(P):
def f(self):
return 'R.f'
r = R()
self.failUnlessEqual ('R.f', r.f())
if __name__ == "__main__":
# remove the option which upsets unittest