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:
41
include/boost/python/detail/nullary_function_adaptor.hpp
Executable file
41
include/boost/python/detail/nullary_function_adaptor.hpp
Executable 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
|
||||
127
include/boost/python/pure_virtual.hpp
Executable file
127
include/boost/python/pure_virtual.hpp
Executable 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
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user