2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-21 05:02:17 +00:00

New function invocation mechanism. This is the major groundwork for handling virtual functions with default implementations properly

[SVN r16388]
This commit is contained in:
Dave Abrahams
2002-11-24 02:43:24 +00:00
parent 05ce65d9d2
commit e14e4e156c
13 changed files with 563 additions and 189 deletions

View File

@@ -107,12 +107,8 @@ namespace detail
};
}
//
// class_<T,Bases,HolderGenerator>
//
// This is the primary mechanism through which users will expose
// C++ classes to Python. The three template arguments are:
//
// This is the primary mechanism through which users will expose
// C++ classes to Python.
template <
class T // class being wrapped
, class X1 // = detail::not_specified

View File

@@ -27,10 +27,15 @@ struct rvalue_from_python_chain
rvalue_from_python_chain* next;
};
struct registration
struct BOOST_PYTHON_DECL registration
{
public: // member functions
explicit registration(type_info);
// Convert the appropriately-typed data to Python
PyObject* to_python(void const volatile*) const;
public: // data members. So sue me.
const python::type_info target_type;
// The chain of eligible from_python converters when an lvalue is required
@@ -39,11 +44,11 @@ struct registration
// The chain of eligible from_python converters when an rvalue is acceptable
rvalue_from_python_chain* rvalue_chain;
// The unique to_python converter for the associated C++ type.
to_python_function_t to_python;
// The class object associated with this type
PyTypeObject* class_object;
// The unique to_python converter for the associated C++ type.
to_python_function_t m_to_python;
};
//
@@ -53,7 +58,7 @@ inline registration::registration(type_info target_type)
: target_type(target_type)
, lvalue_chain(0)
, rvalue_chain(0)
, to_python(0)
, m_to_python(0)
, class_object(0)
{}

View File

@@ -1,3 +1,4 @@
#error obsolete
#if !defined(BOOST_PP_IS_ITERATING)
// (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and

View File

@@ -1,106 +1,175 @@
#if !defined(BOOST_PP_IS_ITERATING)
// (C) Copyright David Abrahams 2000. 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.
//
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
// producing this work.
//
// This file generated for 10-argument member functions and 11-argument free
// functions by gen_caller.python
// Copyright David Abrahams 2002. 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 CALLER_DWA20011214_HPP
# define CALLER_DWA20011214_HPP
# ifndef CALLER_DWA20021121_HPP
# define CALLER_DWA20021121_HPP
# include <boost/compressed_pair.hpp>
# include <boost/mpl/apply.hpp>
# include <boost/mpl/if.hpp>
# include <boost/mpl/size.hpp>
# include <boost/type_traits/is_same.hpp>
# include <boost/python/detail/wrap_python.hpp>
# include <boost/python/detail/returning.hpp>
# include <boost/python/detail/preprocessor.hpp>
# include <boost/type_traits/composite_traits.hpp>
# include <boost/type_traits/same_traits.hpp>
# include <boost/preprocessor/comma_if.hpp>
# include <boost/preprocessor/iterate.hpp>
# include <boost/preprocessor/debug/line.hpp>
# include <boost/preprocessor/iteration/local.hpp>
# include <boost/preprocessor/repetition/enum_trailing_params.hpp>
# include <boost/preprocessor/repetition/repeat.hpp>
# include <boost/preprocessor/cat.hpp>
# include <boost/preprocessor/dec.hpp>
# include <boost/preprocessor/if.hpp>
namespace boost { namespace python
# include <boost/python/detail/invoke.hpp>
namespace boost { namespace python { namespace detail {
// This "result converter" is really just used as
// a dispatch tag to invoke(...), selecting the appropriate
// implementation
typedef int void_result_to_python;
// A metafunction taking an iterator FunctionIter to a metafunction
// class and an iterator ArgIter to an argument, which applies the
// result of dereferencing FunctionIter to the result of dereferencing
// ArgIter
template <class FunctionIter, class ArgIter>
struct apply_iter1
: mpl::apply1<typename FunctionIter::type, typename ArgIter::type> {};
// Given a model of CallPolicies and a C++ result type, this
// metafunction selects the appropriate converter to use for
// converting the result to python.
template <class Policies, class Result>
struct select_result_converter
: mpl::if_<
is_same<Result,void>
, void_result_to_python
, typename mpl::apply1<typename Policies::result_converter,Result>::type*
>
{
template <class T> struct to_python;
}}
namespace boost { namespace python { namespace detail {
struct caller
{
typedef PyObject* result_type;
// function pointers
# define BOOST_PP_ITERATION_PARAMS_1 \
(4, (0, BOOST_PYTHON_MAX_ARITY, <boost/python/detail/caller.hpp>, BOOST_PYTHON_FUNCTION_POINTER))
# include BOOST_PP_ITERATE()
// pointers-to-members
# define BOOST_PP_ITERATION_PARAMS_1 \
(4, (0, 3, <boost/python/detail/caller.hpp>, BOOST_PYTHON_POINTER_TO_MEMBER))
# include BOOST_PP_ITERATE()
};
template <unsigned> struct caller_gen;
# define BOOST_PYTHON_NEXT(init,name,n) \
typedef BOOST_PP_IF(n,typename BOOST_PP_CAT(name,BOOST_PP_DEC(n)) ::next, init) name##n;
# define BOOST_PYTHON_ARG_CONVERTER(n) \
BOOST_PYTHON_NEXT(typename first::next, arg_iter,n) \
BOOST_PYTHON_NEXT(ConverterGenerators, conv_iter,n) \
typedef typename apply_iter1<conv_iter##n,arg_iter##n>::type c_t##n; \
c_t##n c##n(PyTuple_GET_ITEM(args_, n)); \
if (!c##n.convertible()) \
return 0;
# define BOOST_PP_ITERATION_PARAMS_1 \
(3, (0, BOOST_PYTHON_MAX_ARITY + 1, <boost/python/detail/caller.hpp>))
# include BOOST_PP_ITERATE()
# undef BOOST_PYTHON_ARG_CONVERTER
# undef BOOST_PYTHON_NEXT
// A metafunction returning the base class used for caller<class F,
// class ConverterGenerators, class CallPolicies, class Sig>.
template <class F, class ConverterGenerators, class CallPolicies, class Sig>
struct caller_base_select
{
enum { n_arguments = mpl::size<Sig>::value - 1 };
typedef typename caller_gen<n_arguments>::template impl<F,ConverterGenerators,CallPolicies,Sig> type;
};
// A function object type which wraps C++ objects as Python callable
// objects.
//
// Template Arguments:
//
// F -
// the C++ `function object' that will be called. Might
// actually be any data for which an appropriate invoke_tag() can
// be generated. invoke(...) takes care of the actual invocation syntax.
//
// ConverterGenerators -
// An MPL iterator type over a sequence of metafunction classes
// that can be applied to element 1...N of Sig to produce
// argument from_python converters for the arguments
//
// CallPolicies -
// The precall, postcall, and what kind of resultconverter to
// generate for mpl::front<Sig>::type
//
// Sig -
// The `intended signature' of the function. An MPL sequence
// beginning with a result type and continuing with a list of
// argument types.
template <class F, class ConverterGenerators, class CallPolicies, class Sig>
struct caller
: caller_base_select<F,ConverterGenerators,CallPolicies,Sig>::type
{
typedef typename caller_base_select<
F,ConverterGenerators,CallPolicies,Sig
>::type base;
typedef PyObject* result_type;
caller(F f, CallPolicies p) : base(f,p) {}
};
}}} // namespace boost::python::detail
# endif // CALLER_DWA20011214_HPP
# endif // CALLER_DWA20021121_HPP
/* ---------- function pointers --------- */
#elif BOOST_PP_ITERATION_DEPTH() == 1 && BOOST_PP_ITERATION_FLAGS() == BOOST_PYTHON_FUNCTION_POINTER
# line BOOST_PP_LINE(__LINE__, detail/caller.hpp(function pointers))
#else
# define N BOOST_PP_ITERATION()
template <
class P, class R
BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class A)
>
PyObject* operator()(
R (*pf)(BOOST_PP_ENUM_PARAMS_Z(1, N, A))
, PyObject* args
, PyObject* keywords
, P const& policies) const
template <>
struct caller_gen<N>
{
return returning<R>::call(pf, args, keywords, &policies);
}
template <class F, class ConverterGenerators, class Policies, class Sig>
struct impl
{
impl(F f, Policies p) : m_data(f,p) {}
# undef N
PyObject* operator()(PyObject* args_, PyObject*) // eliminate
// this
// trailing
// keyword dict
{
typedef typename mpl::begin<Sig>::type first;
typedef typename first::type result_t;
typedef typename select_result_converter<Policies, result_t>::type result_converter;
# if N
# define BOOST_PP_LOCAL_MACRO(i) BOOST_PYTHON_ARG_CONVERTER(i)
# define BOOST_PP_LOCAL_LIMITS (0, N-1)
# include BOOST_PP_LOCAL_ITERATE()
# endif
// all converters have been checked. Now we can do the
// precall part of the policy
if (!m_data.second().precall(args_))
return 0;
/* ---------- pointers-to-members ---------- */
#elif BOOST_PP_ITERATION_DEPTH() == 1 && BOOST_PP_ITERATION_FLAGS() == BOOST_PYTHON_POINTER_TO_MEMBER
// outer over cv-qualifiers
typedef typename detail::invoke_tag<F>::type tag;
# define BOOST_PP_ITERATION_PARAMS_2 (3, (0, BOOST_PYTHON_MAX_ARITY, <boost/python/detail/caller.hpp>))
# include BOOST_PP_ITERATE()
PyObject* result = detail::invoke(
tag(), result_converter(), m_data.first() BOOST_PP_ENUM_TRAILING_PARAMS(N, c));
return m_data.second().postcall(args_, result);
}
private:
compressed_pair<F,Policies> m_data;
};
};
#elif BOOST_PP_ITERATION_DEPTH() == 2
// inner over arities
#define N BOOST_PP_ITERATION()
#define Q BOOST_PYTHON_CV_QUALIFIER(BOOST_PP_RELATIVE_ITERATION(1))
template <
class P, class R, class T
BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class A)
>
PyObject* operator()(
R (T::*pmf)(BOOST_PP_ENUM_PARAMS_Z(1, N, A)) Q
, PyObject* args, PyObject* keywords
, P const& policies
) const
{
return returning<R>::call(pmf, args, keywords, &policies);
}
#endif // BOOST_PP_IS_ITERATING
#undef N
#undef Q
#endif

View File

@@ -0,0 +1,130 @@
#if !defined(BOOST_PP_IS_ITERATING)
// Copyright David Abrahams 2002. 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 INVOKE_DWA20021122_HPP
# define INVOKE_DWA20021122_HPP
# include <boost/python/detail/wrap_python.hpp>
# include <boost/python/detail/preprocessor.hpp>
# include <boost/python/detail/none.hpp>
# include <boost/python/detail/this_arg_from_python.hpp>
# include <boost/type_traits/is_member_function_pointer.hpp>
# include <boost/preprocessor/iterate.hpp>
# include <boost/preprocessor/facilities/intercept.hpp>
# include <boost/preprocessor/repetition/enum_trailing_params.hpp>
# include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp>
# include <boost/preprocessor/repetition/enum_binary_params.hpp>
# include <boost/python/to_python_value.hpp>
// This file declares a series of overloaded invoke(...) functions,
// used to invoke wrapped C++ function (object)s from Python. Each one
// accepts:
//
// - a tag which identifies the invocation syntax (e.g. member
// functions must be invoked with a different syntax from regular
// functions)
//
// - a pointer to a result converter type, used solely as a way of
// transmitting the type of the result converter to the function (or
// an int, if the return type is void).
//
// - the "function", which may be a function object, a function or
// member function pointer, or a defaulted_virtual_fn.
//
// - The arg_from_python converters for each of the arguments to be
// passed to the function being invoked.
namespace boost { namespace python { namespace detail {
// This "result converter" is really just used as a dispatch tag to
// invoke(...), selecting the appropriate implementation
typedef int void_result_to_python;
// Trait forward declaration.
template <class T> struct is_defaulted_virtual_fn;
// Tag types describing invocation methods
struct fn_tag {};
struct mem_fn_tag {};
struct virtual_fn_tag {};
// A metafunction returning the appropriate tag type for invoking an
// object of type T.
template <class T>
struct invoke_tag
: mpl::if_<
is_member_function_pointer<T>
, mem_fn_tag
, typename mpl::if_<
is_defaulted_virtual_fn<T>
, virtual_fn_tag
, fn_tag
>::type
>
{};
# define BOOST_PP_ITERATION_PARAMS_1 \
(3, (0, BOOST_PYTHON_MAX_ARITY, <boost/python/detail/invoke.hpp>))
# include BOOST_PP_ITERATE()
}}} // namespace boost::python::detail
# endif // INVOKE_DWA20021122_HPP
#else
# define N BOOST_PP_ITERATION()
template <class RC, class F BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class AC)>
inline PyObject* invoke(fn_tag, RC*, F& f BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(1, N, AC, & ac) )
{
return RC()(f( BOOST_PP_ENUM_BINARY_PARAMS_Z(1, N, ac, () BOOST_PP_INTERCEPT) ));
}
template <class F BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class AC)>
inline PyObject* invoke(fn_tag, void_result_to_python, F& f BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(1, N, AC, & ac) )
{
f( BOOST_PP_ENUM_BINARY_PARAMS_Z(1, N, ac, () BOOST_PP_INTERCEPT) );
return none();
}
template <class RC, class F, class TC BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class AC)>
inline PyObject* invoke(mem_fn_tag, RC*, F& f, TC& tc BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(1, N, AC, & ac) )
{
return RC()( (tc().*f)(BOOST_PP_ENUM_BINARY_PARAMS_Z(1, N, ac, () BOOST_PP_INTERCEPT)) );
}
template <class F, class TC BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class AC)>
inline PyObject* invoke(mem_fn_tag, void_result_to_python, F& f, TC& tc BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(1, N, AC, & ac) )
{
(tc().*f)(BOOST_PP_ENUM_BINARY_PARAMS_Z(1, N, ac, () BOOST_PP_INTERCEPT));
return none();
}
template <class RC, class F, class TC BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class AC)>
inline PyObject* invoke(virtual_fn_tag, RC*, F& f, TC& tc BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(1, N, AC, & ac) )
{
return RC()(
tc.use_default()
? f.default_impl(tc() BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(1, N, ac, () BOOST_PP_INTERCEPT))
: (tc().*f.dispatch)(BOOST_PP_ENUM_BINARY_PARAMS_Z(1, N, ac, () BOOST_PP_INTERCEPT)) );
}
template <class F, class TC BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class AC)>
inline PyObject* invoke(virtual_fn_tag, void_result_to_python, F& f, TC& tc BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(1, N, AC, & ac) )
{
if (tc.use_default())
f.default_impl(tc() BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(1, N, ac,()BOOST_PP_INTERCEPT));
else
(tc().*f.dispatch)(BOOST_PP_ENUM_BINARY_PARAMS_Z(1, N, ac,()BOOST_PP_INTERCEPT));
return none();
}
# undef N
#endif // BOOST_PP_IS_ITERATING

View File

@@ -6,38 +6,48 @@
#ifndef MAKE_KEYWORD_RANGE_FN_DWA2002927_HPP
# define MAKE_KEYWORD_RANGE_FN_DWA2002927_HPP
# include <boost/python/make_function.hpp>
# include <boost/python/args_fwd.hpp>
# include <boost/python/detail/caller.hpp>
# include <boost/python/object/function_object.hpp>
# include <boost/python/object/make_holder.hpp>
# include <boost/mpl/size.hpp>
namespace boost { namespace python { namespace detail {
// Think of this as a version of make_function without a compile-time
// check that the size of kw is no greater than the expected arity of
// F. This version is needed when defining functions with default
// arguments, because compile-time information about the number of
// keywords is missing for all but the initial function definition.
template <class F, class Policies>
object make_keyword_range_function(F f, Policies const& policies, keyword_range const& kw)
{
enum { n_arguments = detail::arg_tuple_size<F>::value };
return objects::function_object(
::boost::bind<PyObject*>(detail::caller(), f, _1, _2, policies)
, n_arguments
, kw);
return detail::make_function_aux(
f, policies, args_from_python(), detail::get_signature(f), kw, mpl::int_c<0>());
}
template <class ArgList, class HolderGenerator, class Policies>
// Builds an '__init__' function which inserts the given Holder type
// in a wrapped C++ class instance. ArgList is an MPL type sequence
// describing the C++ argument types to be passed to Holder's
// constructor.
//
// Holder and ArgList are intended to be explicitly specified.
template <class ArgList, class Holder, class CallPolicies>
object make_keyword_range_constructor(
Policies const& policies
, detail::keyword_range const& kw
, HolderGenerator* = 0
CallPolicies const& policies // The CallPolicies with which to invoke the Holder's constructor
, detail::keyword_range const& kw // The (possibly empty) set of associated argument keywords
, Holder* = 0
, ArgList* = 0)
{
enum { nargs = mpl::size<ArgList>::value };
BOOST_STATIC_CONSTANT(unsigned, arity = mpl::size<ArgList>::value);
return objects::function_object(
::boost::bind<PyObject*>(detail::caller(),
objects::make_holder<nargs>
::template apply<HolderGenerator,ArgList>::execute
, _1, _2, policies)
, nargs + 1, kw);
return detail::make_keyword_range_function(
objects::make_holder<arity>
::template apply<Holder,ArgList>::execute
, policies
, kw);
}
}}} // namespace boost::python::detail

View File

@@ -0,0 +1,122 @@
// Copyright David Abrahams 2002. 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 THIS_ARG_FROM_PYTHON_DWA20021122_HPP
# define THIS_ARG_FROM_PYTHON_DWA20021122_HPP
# include <boost/python/arg_from_python.hpp>
# include <boost/python/detail/not_specified.hpp>
# include <boost/mpl/aux_/lambda_support.hpp>
namespace boost { namespace python { namespace detail {
template <class T, class Wrap = not_specified>
struct this_ptr_arg_from_python : converter::arg_lvalue_from_python_base
{
this_ptr_arg_from_python(PyObject* x)
: converter::arg_lvalue_from_python_base(
converter::get_lvalue_from_python(x, converter::registered<T>::converters))
{}
typedef T* result_type;
T* operator()() const
{
return static_cast<T*>(this->result());
}
bool use_default() const
{
return dynamic_cast<Wrap*>((*this)());
}
};
template <class T, class Wrap = not_specified>
struct this_ref_arg_from_python : this_ptr_arg_from_python<T,Wrap>
{
typedef this_ptr_arg_from_python<T,Wrap> base;
this_ref_arg_from_python(PyObject* x) : base(x) {}
typedef T& result_type;
result_type operator()() const
{
return *this->base::operator()();
}
};
// An MPL metafunction class which returns a `this' converter
// appropriate for ArgType, where the target of the member function is
// a class of type T.
template <class T, class Wrap = not_specified>
struct gen_this_from_python
{
// Note: there will almost always be an compile-time error if the
// argument type is neither a reference nor a pointer, since T*
// will be extracted in that case and passed on to the wrapped
// function.
template <class ArgType> struct apply
{
BOOST_STATIC_CONSTANT(
bool, use_ptr
= is_pointer<ArgType>::value
|| boost::python::detail::is_reference_to_pointer<ArgType>::value
&& boost::python::detail::is_reference_to_const<ArgType>::value
&& !boost::python::detail::is_reference_to_volatile<ArgType>::value);
typedef typename mpl::if_c<
use_ptr
, this_ptr_arg_from_python<T,Wrap>
, this_ref_arg_from_python<T,Wrap>
>::type type;
};
};
// An MPL iterator which iterates over a sequence whose first element
// is gen_this_from_python<T> and the remainder of which is an endless
// sequence of gen_arg_from_python
template <class T, class Wrap = not_specified>
struct method_args_from_python
{
typedef gen_this_from_python<T,Wrap> type;
typedef args_from_python next;
};
template <class VirtualFunction, class Default>
struct defaulted_virtual_fn
{
defaulted_virtual_fn(VirtualFunction dispatch, Default const& default_impl)
: dispatch(dispatch), default_impl(default_impl) {};
VirtualFunction dispatch;
Default default_impl;
};
# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
template <class T>
struct is_defaulted_virtual_fn
{ BOOST_STATIC_CONSTANT(bool, value = false); };
template <class T,class U>
struct is_defaulted_virtual_fn<defaulted_virtual_fn<T,U> >
{ BOOST_STATIC_CONSTANT(bool, value = true); };
# else
template <class T>
struct is_defaulted_virtual_fn
{
template <class T, class U>
static char helper(defaulted_virtual_fn<T,U>* x);
static char (& helper(...)) [2];
BOOST_STATIC_CONSTANT(bool, value = sizeof(helper((T*)0)) == 1);
BOOST_MPL_AUX_LAMBDA_SUPPORT(1,is_defaulted_virtual_fn,(T))
};
# endif
}}} // namespace boost::python::detail
#endif // THIS_ARG_FROM_PYTHON_DWA20021122_HPP

View File

@@ -6,74 +6,98 @@
#ifndef MAKE_FUNCTION_DWA20011221_HPP
# define MAKE_FUNCTION_DWA20011221_HPP
# include <boost/python/object/function_object.hpp>
# include <boost/python/args_fwd.hpp>
# include <boost/python/object/make_holder.hpp>
# include <boost/python/detail/caller.hpp>
# include <boost/python/detail/arg_tuple_size.hpp>
# include <boost/mpl/size.hpp>
# include <boost/bind.hpp>
# include <boost/python/default_call_policies.hpp>
# include <boost/python/args_fwd.hpp>
# include <boost/python/detail/caller.hpp>
# include <boost/python/object/function_object.hpp>
# include <boost/mpl/size.hpp>
# include <boost/mpl/int_c.hpp>
namespace boost { namespace python {
namespace detail
{
// make_function_aux --
//
// These helper functions for make_function (below) do the raw work
// of constructing a Python object from some invokable entity. See
// <boost/python/detail/caller.hpp> for more information about how
// the ConverterGenerators and Sig arguments are used.
template <class F, class CallPolicies, class ConverterGenerators, class Sig>
object make_function_aux(
F f // An object that can be invoked by detail::invoke()
, CallPolicies const& p // CallPolicies to use in the invocation
, ConverterGenerators const& // An MPL iterator over a sequence of arg_from_python generators
, Sig const& // An MPL sequence of argument types expected by F
)
{
return objects::function_object(
detail::caller<F,ConverterGenerators,CallPolicies,Sig>(f, p)
, mpl::size<Sig>::value - 1);
}
// As above, except that it accepts argument keywords. NumKeywords
// is used only for a compile-time assertion to make sure the user
// doesn't pass more keywords than the function can accept. To
// disable all checking, pass mpl::int_c<0> for NumKeywords.
template <class F, class CallPolicies, class ConverterGenerators, class Sig, class NumKeywords>
object make_function_aux(
F f
, CallPolicies const& p
, ConverterGenerators const&
, Sig const&
, detail::keyword_range const& kw // a [begin,end) pair of iterators over keyword names
, NumKeywords // An MPL integral type wrapper: the size of kw
)
{
enum { arity = mpl::size<Sig>::value - 1 };
typedef typename detail::error::more_keywords_than_function_arguments<
NumKeywords::value, arity
>::too_many_keywords assertion;
return objects::function_object(
detail::caller<F,ConverterGenerators,CallPolicies,Sig>(f, p)
, arity
, kw);
}
}
// make_function --
//
// These overloaded functions wrap a function or member function
// pointer as a Python object, using optional CallPolicies and
// Keywords.
template <class F>
object make_function(F f)
{
return objects::function_object(
::boost::bind<PyObject*>(detail::caller(), f, _1, _2, default_call_policies())
, detail::arg_tuple_size<F>::value);
return detail::make_function_aux(
f,default_call_policies(),detail::args_from_python(), detail::get_signature(f));
}
template <class F, class Policies>
object make_function(F f, Policies const& policies)
template <class F, class CallPolicies>
object make_function(F f, CallPolicies const& policies)
{
return objects::function_object(
::boost::bind<PyObject*>(detail::caller(), f, _1, _2, policies)
, detail::arg_tuple_size<F>::value);
return detail::make_function_aux(
f,policies,detail::args_from_python(), detail::get_signature(f));
}
template <class F, class Policies, class Keywords>
object make_function(F f, Policies const& policies, Keywords const& keywords)
template <class F, class CallPolicies, class Keywords>
object make_function(F f, CallPolicies const& policies, Keywords const& keywords)
{
enum { n_arguments = detail::arg_tuple_size<F>::value };
typedef typename detail::error::more_keywords_than_function_arguments<
Keywords::size, n_arguments
>::too_many_keywords assertion;
return objects::function_object(
::boost::bind<PyObject*>(detail::caller(), f, _1, _2, policies)
, n_arguments
, keywords.range());
return detail::make_function_aux(
f
, policies
, detail::args_from_python()
, detail::get_signature(f)
, keywords.range()
, mpl::int_c<Keywords::size>()
);
}
template <class ArgList, class HolderGenerator>
object make_constructor(HolderGenerator* = 0, ArgList* = 0)
{
enum { nargs = mpl::size<ArgList>::value };
return objects::function_object(
::boost::bind<PyObject*>(
detail::caller()
, objects::make_holder<nargs>
::template apply<HolderGenerator,ArgList>::execute
, _1, _2, default_call_policies())
, nargs + 1);
}
}}
template <class ArgList, class HolderGenerator, class Policies>
object make_constructor(Policies const& policies, HolderGenerator* = 0, ArgList* = 0)
{
enum { nargs = mpl::size<ArgList>::value };
return objects::function_object(
::boost::bind<PyObject*>(detail::caller(),
objects::make_holder<nargs>
::template apply<HolderGenerator,ArgList>::execute
, _1, _2, policies)
, nargs + 1);
}
}} // namespace boost::python
#endif // MAKE_FUNCTION_DWA20011221_HPP

View File

@@ -7,10 +7,9 @@
# define FUNCTION_HANDLE_DWA2002725_HPP
# include <boost/python/handle.hpp>
# include <boost/python/detail/caller.hpp>
# include <boost/python/detail/arg_tuple_size.hpp>
# include <boost/python/default_call_policies.hpp>
# include <boost/python/object/py_function.hpp>
# include <boost/bind.hpp>
# include <boost/python/signature.hpp>
namespace boost { namespace python { namespace objects {
@@ -19,10 +18,16 @@ BOOST_PYTHON_DECL handle<> function_handle_impl(py_function const& f, unsigned m
// Just like function_object, but returns a handle<> instead. Using
// this for arg_to_python<> allows us to break a circular dependency
// between object and arg_to_python.
template <class F>
inline handle<> function_handle(F const& f, unsigned min_args, unsigned max_args = 0)
template <class F, class Signature>
inline handle<> function_handle(F const& f, Signature)
{
return objects::function_handle_impl(objects::py_function(f), min_args, max_args);
enum { n_arguments = mpl::size<Signature>::value - 1 };
return objects::function_handle_impl(
python::detail::caller<
F,python::detail::args_from_python,default_call_policies,Signature>(
f, default_call_policies())
, n_arguments, n_arguments);
}
// Just like make_function, but returns a handle<> intead. Same
@@ -30,9 +35,7 @@ inline handle<> function_handle(F const& f, unsigned min_args, unsigned max_args
template <class F>
handle<> make_function_handle(F f)
{
return objects::function_handle(
::boost::bind<PyObject*>(python::detail::caller(), f, _1, _2, default_call_policies())
, python::detail::arg_tuple_size<F>::value);
return objects::function_handle(f, python::detail::get_signature(f));
}
}}} // namespace boost::python::objects

View File

@@ -12,26 +12,23 @@
namespace boost { namespace python { namespace converter {
namespace
PyObject* registration::to_python(void const volatile* source) const
{
inline PyObject* convert_to_python(void const volatile* source, registration const& converters)
if (this->m_to_python == 0)
{
if (converters.to_python == 0)
{
handle<> msg(
::PyString_FromFormat(
"No to_python (by-value) converter found for C++ type: %s"
, converters.target_type.name()));
handle<> msg(
::PyString_FromFormat(
"No to_python (by-value) converter found for C++ type: %s"
, this->target_type.name()));
PyErr_SetObject(PyExc_TypeError, msg.get());
PyErr_SetObject(PyExc_TypeError, msg.get());
throw_error_already_set();
}
return source == 0
? incref(Py_None)
: converters.to_python(const_cast<void*>(source));
throw_error_already_set();
}
return source == 0
? incref(Py_None)
: this->m_to_python(const_cast<void*>(source));
}
namespace detail
@@ -39,10 +36,11 @@ namespace detail
arg_to_python_base::arg_to_python_base(
void const volatile* source, registration const& converters)
# if !defined(BOOST_MSVC) || BOOST_MSVC <= 1300 || _MSC_FULL_VER > 13102179
: handle<>(converter::convert_to_python(source, converters))
: handle<>
# else
: m_ptr(converter::convert_to_python(source, converters))
# endif
: m_ptr
# endif
(converters.to_python(source))
{
}

View File

@@ -69,7 +69,7 @@ namespace registry
# ifdef BOOST_PYTHON_TRACE_REGISTRY
std::cout << "inserting to_python " << source_t << "\n";
# endif
to_python_function_t& slot = get(source_t)->to_python;
to_python_function_t& slot = get(source_t)->m_to_python;
assert(slot == 0); // we have a problem otherwise
if (slot != 0)

View File

@@ -199,6 +199,9 @@ D take_d_shared_ptr(boost::shared_ptr<D> d) { return *d; }
boost::shared_ptr<A> d_factory() { return boost::shared_ptr<B>(new D); }
struct Unregistered {};
Unregistered make_unregistered(int) { return Unregistered(); }
BOOST_PYTHON_MODULE(m1)
{
using namespace boost::python;
@@ -222,6 +225,8 @@ BOOST_PYTHON_MODULE(m1)
def("new_noddy", new_noddy);
def("new_simple", new_simple);
def("make_unregistered", make_unregistered);
// Expose f() in all its variations
def("f", f);
def("f_mutable_ref", f_mutable_ref);

View File

@@ -3,6 +3,17 @@
>>> from m2 import *
Prove that we get an appropriate error from trying to return a type
for which we have no registered to_python converter
>>> try:
... make_unregistered(1)
... except TypeError, x:
... if not str(x).startswith('No to_python (by-value) converter found for C++ type'):
... print str(x)
... else:
... print 'expected a TypeError'
>>> n = new_noddy()
>>> s = new_simple()
>>> unwrap_int(n)