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

Support for wrapping function objects and classes which use virtual

inheritance.  Completely killed off member_function_cast!


[SVN r19945]
This commit is contained in:
Dave Abrahams
2003-09-07 16:56:05 +00:00
parent 4a7b8fe839
commit b3910f4e4d
10 changed files with 340 additions and 375 deletions

View File

@@ -29,7 +29,6 @@
# include <boost/python/detail/overloads_fwd.hpp>
# include <boost/python/detail/operator_id.hpp>
# include <boost/python/detail/member_function_cast.hpp>
# include <boost/python/detail/def_helper.hpp>
# include <boost/python/detail/force_instantiate.hpp>
@@ -363,56 +362,28 @@ class class_ : public objects::class_base
template <class Get>
self& add_property(char const* name, Get fget)
{
base::add_property(
name
, object(
detail::member_function_cast<T,Get>::stage1(fget).stage2((T*)0).stage3(fget)
)
);
base::add_property(name, make_fn(fget));
return *this;
}
template <class Get, class Set>
self& add_property(char const* name, Get fget, Set fset)
{
base::add_property(
name
, object(
detail::member_function_cast<T,Get>::stage1(fget).stage2((T*)0).stage3(fget)
)
, object(
detail::member_function_cast<T,Set>::stage1(fset).stage2((T*)0).stage3(fset)
)
);
base::add_property(name, make_fn(fget), make_fn(fset));
return *this;
}
template <class Get>
self& add_static_property(char const* name, Get fget)
{
base::add_static_property(
name
, object(
detail::member_function_cast<T,Get>::stage1(fget).stage2((T*)0).stage3(fget)
)
);
base::add_static_property(name, object(fget));
return *this;
}
template <class Get, class Set>
self& add_static_property(char const* name, Get fget, Set fset)
{
base::add_static_property(
name
, object(
detail::member_function_cast<T,Get>::stage1(fget).stage2((T*)0).stage3(fget)
)
, object(
detail::member_function_cast<T,Set>::stage1(fset).stage2((T*)0).stage3(fset)
)
);
base::add_static_property(name, object(fget), object(fset));
return *this;
}
@@ -444,6 +415,30 @@ class class_ : public objects::class_base
}
private: // helper functions
// Builds a method for this class around the given [member]
// function pointer or object, appropriately adjusting the type of
// the first signature argument so that if f is a member of a
// (possibly not wrapped) base class of T, an lvalue argument of
// type T will be required.
//
// {
template <class F>
object make_fn(F const& f)
{
return make_function(f, default_call_policies(), detail::get_signature(f, (T*)0));
}
object
# if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
const&
# endif
make_fn(object const& x)
{
return x;
}
// }
template <class D, class B>
self& def_readonly_impl(
char const* name, D B::*pm_ BOOST_PYTHON_YES_DATA_MEMBER)
@@ -501,12 +496,16 @@ class class_ : public objects::class_base
)
{
objects::add_to_namespace(
*this, name,
make_function(
// This bit of nastiness casts F to a member function of T if possible.
detail::member_function_cast<T,Fn>::stage1(fn).stage2((T*)0).stage3(fn)
, helper.policies(), helper.keywords())
, helper.doc());
*this
, name
, make_function(
fn
, helper.policies()
, helper.keywords()
, detail::get_signature(fn, (T*)0)
)
, helper.doc()
);
this->def_default(name, fn, helper, mpl::bool_<Helper::has_default_implementation>());
}

View File

@@ -37,8 +37,13 @@ namespace objects
namespace detail
{
template <class T, class F> struct member_function_cast;
// Called as::
//
// name_space_def(ns, "func", func, kw, policies, docstring, &ns)
//
// Dispatch to properly add f to namespace ns.
//
// { define_stub_function helpers
template <class Func, class CallPolicies, class NameSpaceT>
static void name_space_def(
NameSpaceT& name_space
@@ -55,10 +60,9 @@ namespace detail
objects::add_to_namespace(
name_space, name,
detail::make_keyword_range_function(
// This bit of nastiness casts F to a member function of T if possible.
member_function_cast<wrapped_type,Func>::stage1(f).stage2((wrapped_type*)0).stage3(f)
, policies, kw)
, doc);
f, policies, kw, get_signature(f, (wrapped_type*)0))
, doc
);
}
template <class Func, class CallPolicies>
@@ -80,7 +84,7 @@ namespace detail
, doc);
}
// For backward compatibility
// For backward compatibility -- is this obsolete?
template <class Func, class CallPolicies, class NameSpaceT>
static void name_space_def(
NameSpaceT& name_space
@@ -94,10 +98,10 @@ namespace detail
{
name_space.def(name, f, policies, doc);
}
// }
///////////////////////////////////////////////////////////////////////////////
//
// This Boost PP code generates expansions for
// Expansions of ::
//
// template <typename OverloadsT, typename NameSpaceT>
// inline void
@@ -107,7 +111,7 @@ namespace detail
// name_space.def(name, &OverloadsT::func_N);
// }
//
// where N runs from 0 to BOOST_PYTHON_MAX_ARITY
// where N runs from 0 to BOOST_PYTHON_MAX_ARITY.
//
// The set of overloaded functions (define_stub_function) expects:
//
@@ -118,7 +122,7 @@ namespace detail
// (see defaults_gen.hpp)
// 5. char const* name: doc string
//
///////////////////////////////////////////////////////////////////////////////
// {
template <int N>
struct define_stub_function {};
@@ -126,129 +130,137 @@ namespace detail
(3, (0, BOOST_PYTHON_MAX_ARITY, <boost/python/detail/defaults_def.hpp>))
#include BOOST_PP_ITERATE()
// }
// This helper template struct does the actual recursive
// definition. There's a generic version
// define_with_defaults_helper<N> and a terminal case
// define_with_defaults_helper<0>. The struct and its
// specialization has a sole static member function def that
// expects:
//
// 1. char const* name: function name that will be
// visible to python
//
// 2. OverloadsT: a function overloads struct
// (see defaults_gen.hpp)
//
// 3. NameSpaceT& name_space: a python::class_ or
// python::module instance
//
// 4. char const* name: doc string
//
// The def static member function calls a corresponding
// define_stub_function<N>. The general case recursively calls
// define_with_defaults_helper<N-1>::def until it reaches the
// terminal case case define_with_defaults_helper<0>.
template <int N>
struct define_with_defaults_helper {
///////////////////////////////////////////////////////////////////////////////
//
// define_with_defaults_helper<N>
//
// This helper template struct does the actual recursive definition.
// There's a generic version define_with_defaults_helper<N> and a
// terminal case define_with_defaults_helper<0>. The struct and its
// specialization has a sole static member function def that expects:
//
// 1. char const* name: function name that will be visible to python
// 2. OverloadsT: a function overloads struct (see defaults_gen.hpp)
// 3. NameSpaceT& name_space: a python::class_ or python::module instance
// 4. char const* name: doc string
//
// The def static member function calls a corresponding
// define_stub_function<N>. The general case recursively calls
// define_with_defaults_helper<N-1>::def until it reaches the
// terminal case case define_with_defaults_helper<0>.
//
///////////////////////////////////////////////////////////////////////////////
template <int N>
struct define_with_defaults_helper {
template <class StubsT, class CallPolicies, class NameSpaceT>
static void
def(
char const* name,
StubsT stubs,
keyword_range kw,
CallPolicies const& policies,
NameSpaceT& name_space,
char const* doc)
{
// define the NTH stub function of stubs
define_stub_function<N>::define(name, stubs, kw, policies, name_space, doc);
template <class StubsT, class CallPolicies, class NameSpaceT>
static void
def(
char const* name,
StubsT stubs,
keyword_range kw,
CallPolicies const& policies,
NameSpaceT& name_space,
char const* doc)
{
// define the NTH stub function of stubs
define_stub_function<N>::define(name, stubs, kw, policies, name_space, doc);
if (kw.second > kw.first)
--kw.second;
// call the next define_with_defaults_helper
define_with_defaults_helper<N-1>::def(name, stubs, kw, policies, name_space, doc);
}
};
if (kw.second > kw.first)
--kw.second;
///////////////////////////////////////
template <>
struct define_with_defaults_helper<0> {
// call the next define_with_defaults_helper
define_with_defaults_helper<N-1>::def(name, stubs, kw, policies, name_space, doc);
}
};
template <class StubsT, class CallPolicies, class NameSpaceT>
static void
def(
char const* name,
StubsT stubs,
keyword_range const& kw,
CallPolicies const& policies,
NameSpaceT& name_space,
char const* doc)
{
// define the Oth stub function of stubs
define_stub_function<0>::define(name, stubs, kw, policies, name_space, doc);
// return
}
};
template <>
struct define_with_defaults_helper<0> {
///////////////////////////////////////////////////////////////////////////////
//
// define_with_defaults
//
// 1. char const* name: function name that will be visible to python
// 2. OverloadsT: a function overloads struct (see defaults_gen.hpp)
// 3. CallPolicies& policies: Call policies
// 4. NameSpaceT& name_space: a python::class_ or python::module instance
// 5. SigT sig: Function signature typelist (see defaults_gen.hpp)
// 6. char const* name: doc string
//
// This is the main entry point. This function recursively defines all
// stub functions of StubT (see defaults_gen.hpp) in NameSpaceT name_space which
// can be either a python::class_ or a python::module. The sig argument
// is a typelist that specifies the return type, the class (for member
// functions, and the arguments. Here are some SigT examples:
//
// int foo(int) mpl::list<int, int>
// void bar(int, int) mpl::list<void, int, int>
// void C::foo(int) mpl::list<void, C, int>
//
///////////////////////////////////////////////////////////////////////////////
template <class OverloadsT, class NameSpaceT, class SigT>
inline void
define_with_defaults(
char const* name,
OverloadsT const& overloads,
NameSpaceT& name_space,
SigT const&)
{
typedef typename mpl::front<SigT>::type return_type;
typedef typename OverloadsT::void_return_type void_return_type;
typedef typename OverloadsT::non_void_return_type non_void_return_type;
template <class StubsT, class CallPolicies, class NameSpaceT>
static void
def(
char const* name,
StubsT stubs,
keyword_range const& kw,
CallPolicies const& policies,
NameSpaceT& name_space,
char const* doc)
{
// define the Oth stub function of stubs
define_stub_function<0>::define(name, stubs, kw, policies, name_space, doc);
// return
}
};
typedef typename mpl::if_c<
boost::is_same<void, return_type>::value
, void_return_type
, non_void_return_type
>::type stubs_type;
// define_with_defaults
//
// 1. char const* name: function name that will be
// visible to python
//
// 2. OverloadsT: a function overloads struct
// (see defaults_gen.hpp)
//
// 3. CallPolicies& policies: Call policies
// 4. NameSpaceT& name_space: a python::class_ or
// python::module instance
//
// 5. SigT sig: Function signature typelist
// (see defaults_gen.hpp)
//
// 6. char const* name: doc string
//
// This is the main entry point. This function recursively
// defines all stub functions of StubT (see defaults_gen.hpp) in
// NameSpaceT name_space which can be either a python::class_ or
// a python::module. The sig argument is a typelist that
// specifies the return type, the class (for member functions,
// and the arguments. Here are some SigT examples:
//
// int foo(int) mpl::vector<int, int>
// void bar(int, int) mpl::vector<void, int, int>
// void C::foo(int) mpl::vector<void, C, int>
//
template <class OverloadsT, class NameSpaceT, class SigT>
inline void
define_with_defaults(
char const* name,
OverloadsT const& overloads,
NameSpaceT& name_space,
SigT const&)
{
typedef typename mpl::front<SigT>::type return_type;
typedef typename OverloadsT::void_return_type void_return_type;
typedef typename OverloadsT::non_void_return_type non_void_return_type;
BOOST_STATIC_ASSERT(
(stubs_type::max_args) <= mpl::size<SigT>::value);
typedef typename mpl::if_c<
boost::is_same<void, return_type>::value
, void_return_type
, non_void_return_type
>::type stubs_type;
typedef typename stubs_type::template gen<SigT> gen_type;
define_with_defaults_helper<stubs_type::n_funcs-1>::def(
name
, gen_type()
, overloads.keywords()
, overloads.call_policies()
, name_space
, overloads.doc_string());
}
BOOST_STATIC_ASSERT(
(stubs_type::max_args) <= mpl::size<SigT>::value);
typedef typename stubs_type::template gen<SigT> gen_type;
define_with_defaults_helper<stubs_type::n_funcs-1>::def(
name
, gen_type()
, overloads.keywords()
, overloads.call_policies()
, name_space
, overloads.doc_string());
}
} // namespace detail
}} // namespace boost::python
///////////////////////////////////////////////////////////////////////////////
#endif // DEFAULTS_DEF_JDG20020811_HPP
#else // defined(BOOST_PP_IS_ITERATING)

View File

@@ -21,13 +21,30 @@ namespace boost { namespace python { namespace detail {
// 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)
object make_keyword_range_function(
F f
, Policies const& policies
, keyword_range const& kw)
{
return detail::make_function_aux(
f, policies, args_from_python(), detail::get_signature(f), kw, mpl::int_<0>());
}
template <class F, class Policies, class Signature>
object make_keyword_range_function(
F f
, Policies const& policies
, keyword_range const& kw
, Signature const& sig)
{
return detail::make_function_aux(
f, policies, args_from_python(), sig, kw, mpl::int_<0>());
}
// }
// 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

View File

@@ -1,118 +0,0 @@
#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 MEMBER_FUNCTION_CAST_DWA2002311_HPP
# define MEMBER_FUNCTION_CAST_DWA2002311_HPP
# include <boost/python/detail/preprocessor.hpp>
# include <boost/mpl/if.hpp>
# include <boost/type_traits/composite_traits.hpp>
# include <boost/preprocessor/comma_if.hpp>
# include <boost/preprocessor/iterate.hpp>
# include <boost/preprocessor/debug/line.hpp>
# include <boost/preprocessor/repetition/enum_params.hpp>
# include <boost/preprocessor/repetition/enum_trailing_params.hpp>
namespace boost { namespace python { namespace detail {
template <class S, class FT>
struct cast_helper
{
struct yes_helper
{
static FT stage3(FT x) { return x; }
};
struct no_helper
{
template <class T>
static T stage3(T x) { return x; }
};
static yes_helper stage2(S*) { return yes_helper(); }
static no_helper stage2(void*) { return no_helper(); }
};
struct non_member_function_cast_impl
{
template <class T>
static non_member_function_cast_impl stage1(T) { return non_member_function_cast_impl(); }
template <class T>
static non_member_function_cast_impl stage2(T) { return non_member_function_cast_impl(); }
template <class T>
T stage3(T x) { return x; }
};
template <class T>
struct member_function_cast_impl
{
# ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
template <class U>
static non_member_function_cast_impl stage1(U)
{
return non_member_function_cast_impl();
}
# endif
// Member functions
# define BOOST_PP_ITERATION_PARAMS_1 (3, (0, 3, <boost/python/detail/member_function_cast.hpp>))
# include BOOST_PP_ITERATE()
};
template <class T, class SF>
struct member_function_cast
# ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
: member_function_cast_impl<T>
# else
: mpl::if_c<
is_member_function_pointer<SF>::value
, member_function_cast_impl<T>
, non_member_function_cast_impl
>::type
# endif
{
};
}}} // namespace boost::python::detail
# endif // MEMBER_FUNCTION_CAST_DWA2002311_HPP
#elif BOOST_PP_ITERATION_DEPTH() == 1
// outer over cv-qualifiers
# define BOOST_PP_ITERATION_PARAMS_2 (3, (0, BOOST_PYTHON_MAX_ARITY, <boost/python/detail/member_function_cast.hpp>))
# include BOOST_PP_ITERATE()
#elif BOOST_PP_ITERATION_DEPTH() == 2
# line BOOST_PP_LINE(__LINE__, member_function_cast.hpp)
// inner over arities
# define N BOOST_PP_ITERATION()
# define Q BOOST_PYTHON_CV_QUALIFIER(BOOST_PP_RELATIVE_ITERATION(1))
# define P BOOST_PP_ENUM_PARAMS_Z(1, N, A)
template <
class S, class R
BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class A)
>
static cast_helper<S, R (T::*)( P ) Q>
stage1(R (S::*)( P ) Q)
{
return cast_helper<S, R (T::*)( P ) Q>();
}
# undef P
# undef N
# undef Q
#endif

View File

@@ -9,7 +9,7 @@
# include <boost/python/detail/prefix.hpp>
# include <boost/python/default_call_policies.hpp>
# include <boost/python/args_fwd.hpp>
# include <boost/python/args.hpp>
# include <boost/python/detail/caller.hpp>
# include <boost/python/object/function_object.hpp>
@@ -64,13 +64,41 @@ namespace detail
detail::caller<F,ConverterGenerators,CallPolicies,Sig>(f, p)
, kw);
}
}
// make_function --
//
// These overloaded functions wrap a function or member function
// pointer as a Python object, using optional CallPolicies and
// Keywords.
// { Helpers for make_function when called with 3 arguments. These
// dispatch functions are used to discriminate between the cases
// when the 3rd argument is keywords or when it is a signature.
//
template <class F, class CallPolicies, class Keywords>
object make_function_dispatch(F f, CallPolicies const& policies, Keywords const& kw, mpl::true_)
{
return detail::make_function_aux(
f
, policies
, detail::args_from_python()
, detail::get_signature(f)
, kw.range()
, mpl::int_<Keywords::size>()
);
}
template <class F, class CallPolicies, class Signature>
object make_function_dispatch(F f, CallPolicies const& policies, Signature const& sig, mpl::false_)
{
return detail::make_function_aux(
f
, policies
, detail::args_from_python()
, sig
);
}
// }
}
// { These overloaded functions wrap a function or member function
// pointer as a Python object, using optional CallPolicies,
// Keywords, and/or Signature.
template <class F>
object make_function(F f)
{
@@ -85,18 +113,42 @@ object make_function(F f, CallPolicies const& policies)
f,policies,detail::args_from_python(), detail::get_signature(f));
}
template <class F, class CallPolicies, class Keywords>
object make_function(F f, CallPolicies const& policies, Keywords const& keywords)
template <class F, class CallPolicies, class KeywordsOrSignature>
object make_function(
F f
, CallPolicies const& policies
, KeywordsOrSignature const& keywords_or_signature)
{
typedef typename
detail::is_reference_to_keywords<KeywordsOrSignature&>::type
is_kw;
return detail::make_function_dispatch(
f
, policies
, keywords_or_signature
, is_kw()
);
}
template <class F, class CallPolicies, class Keywords, class Signature>
object make_function(
F f
, CallPolicies const& policies
, Keywords const& kw
, Signature const& sig
)
{
return detail::make_function_aux(
f
f
, policies
, detail::args_from_python()
, detail::get_signature(f)
, keywords.range()
, sig
, kw.range()
, mpl::int_<Keywords::size>()
);
);
}
// }
}}

View File

@@ -44,9 +44,9 @@ namespace detail
>::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&.
// 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))
@@ -97,10 +97,9 @@ namespace detail
// Add the default implementation which raises the exception
c.def(
name
, detail::make_function_aux(
, make_function(
detail::nullary_function_adaptor<void(*)()>(pure_virtual_called)
, default_call_policies()
, args_from_python()
, detail::error_signature<held_t>(detail::get_signature(m_pmf))
)
);

View File

@@ -14,6 +14,9 @@
# include <boost/python/detail/prefix.hpp>
# include <boost/mpl/if.hpp>
# include <boost/type_traits/is_convertible.hpp>
# include <boost/python/detail/preprocessor.hpp>
# include <boost/preprocessor/repeat.hpp>
# include <boost/preprocessor/enum.hpp>
@@ -34,48 +37,80 @@
///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace python { namespace detail {
///////////////////////////////////////////////////////////////////////////////
//
// The following macros generate expansions for:
// A metafunction returning C1 if C1 is derived from C2, and C2
// otherwise
template <class C1, class C2>
struct most_derived
{
typedef typename mpl::if_<
is_convertible<C1*,C2*>
, C1
, C2
>::type type;
};
// {
// The following macros generate expansions for::
//
// template <class RT, class T0... class TN>
// inline mpl::list<RT, T0...TN>
// get_signature(RT(*)(T0...TN))
// inline mpl::vector<RT, T0...TN>
// get_signature(RT(*)(T0...TN), void* = 0)
// {
// return mpl::list<RT, T0...TN>();
// }
//
// And, for an appropriate assortment of cv-qualifications
// And, for an appropriate assortment of cv-qualifications::
//
// template <class RT, class ClassT, class T0... class TN>
// inline mpl::list<RT, ClassT cv&, T0...TN>
// inline mpl::vector<RT, ClassT&, T0...TN>
// get_signature(RT(ClassT::*)(T0...TN) cv))
// {
// return mpl::list<RT, ClassT&, T0...TN>();
// }
//
// These functions extract the return type, class (for member
// functions) and arguments of the input signature and stuffs them in
// an mpl::list. Note that cv-qualification is dropped from the
// target class; that is a necessary sacrifice to ensure that an
// lvalue from_python converter is used.
// template <class Target, class RT, class ClassT, class T0... class TN>
// inline mpl::vector<
// RT
// , typename most_derived<Target, ClassT>::type&
// , T0...TN
// >
// get_signature(RT(ClassT::*)(T0...TN) cv), Target*)
// {
// return mpl::list<RT, ClassT&, T0...TN>();
// }
//
///////////////////////////////////////////////////////////////////////////////
// There are two forms for invoking get_signature::
//
// get_signature(f)
//
// and ::
//
// get_signature(f,(Target*)0)
//
// These functions extract the return type, class (for member
// functions) and arguments of the input signature and stuff them in
// an mpl type sequence. Note that cv-qualification is dropped from
// the "hidden this" argument of member functions; that is a
// necessary sacrifice to ensure that an lvalue from_python converter
// is used. A pointer is not used so that None will be rejected for
// overload resolution.
//
// The second form of get_signature essentially downcasts the "hidden
// this" argument of member functions to Target, because the function
// may actually be a member of a base class which is not wrapped, and
// in that case conversion from python would fail.
///////////////////////////////////////////////////////////////////////////////
# define BOOST_PP_ITERATION_PARAMS_1 \
(3, (0, BOOST_PYTHON_MAX_ARITY, <boost/python/signature.hpp>))
# include BOOST_PP_ITERATE()
# undef BOOST_PYTHON_LIST_INC
}
// }
}} // namespace boost::python
}}} // namespace boost::python::detail
# undef BOOST_PYTHON_LIST_INC
///////////////////////////////////////////////////////////////////////////////
# endif // SIGNATURE_JDG20020813_HPP
#elif BOOST_PP_ITERATION_DEPTH() == 1 // defined(BOOST_PP_IS_ITERATING)
@@ -86,7 +121,7 @@ template <
class RT BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class T)>
inline BOOST_PYTHON_LIST_INC(N)<
RT BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, T)>
get_signature(RT(*)(BOOST_PP_ENUM_PARAMS_Z(1, N, T)))
get_signature(RT(*)(BOOST_PP_ENUM_PARAMS_Z(1, N, T)), void* = 0)
{
return BOOST_PYTHON_LIST_INC(N)<
RT BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, T)
@@ -115,6 +150,29 @@ get_signature(RT(ClassT::*)(BOOST_PP_ENUM_PARAMS_Z(1, N, T)) Q)
>();
}
template <
class Target
, class RT
, class ClassT
BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class T)
>
inline BOOST_PYTHON_LIST_INC(BOOST_PP_INC(N))<
RT
, typename most_derived<Target, ClassT>::type&
BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, T)
>
get_signature(
RT(ClassT::*)(BOOST_PP_ENUM_PARAMS_Z(1, N, T)) Q
, Target*
)
{
return BOOST_PYTHON_LIST_INC(BOOST_PP_INC(N))<
RT
, BOOST_DEDUCED_TYPENAME most_derived<Target, ClassT>::type&
BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, T)
>();
}
# undef Q
# undef N

View File

@@ -161,7 +161,6 @@ local UNIT_TEST_PROPERTIES = $(PYTHON_PROPERTIES) <define>BOOST_PYTHON_SUPPRESS_
run indirect_traits_test.cpp ;
run destroy_test.cpp ;
run pointer_type_id_test.cpp <lib>../../test/build/boost_test_exec_monitor : : : $(UNIT_TEST_PROPERTIES) ;
run member_function_cast.cpp ;
run bases.cpp : : : $(UNIT_TEST_PROPERTIES) ;
run if_else.cpp ;
run pointee.cpp : : : $(UNIT_TEST_PROPERTIES) ;

View File

@@ -1,55 +0,0 @@
// 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.
#include <boost/python/detail/member_function_cast.hpp>
#include <boost/type_traits.hpp>
#include <boost/type.hpp>
#include <boost/static_assert.hpp>
using namespace boost;
template <class T, class S>
void assert_same(S, type<T>* = 0)
{
BOOST_STATIC_ASSERT((is_same<T,S>::value));
}
template <class Expected, class Target, class F>
void assert_mf_cast(F f, type<Expected>* = 0, type<Target>* = 0)
{
assert_same<Expected>(
python::detail::member_function_cast<Target,F>::stage1(f).stage2((Target*)0).stage3(f)
);
}
struct X
{
int f() const { return 0; }
void g(char*) {}
};
struct Y : X
{
};
struct Z : Y
{
int f() const { return 0; }
void g(char*) {}
};
int main()
{
assert_mf_cast<int (Y::*)() const, Y>(&X::f);
assert_mf_cast<void (Y::*)(char*), Y>(&X::g);
assert_mf_cast<int (Z::*)() const, Y>(&Z::f);
assert_mf_cast<void (Z::*)(char*), Y>(&Z::g);
assert_mf_cast<int, Y>(3);
assert_mf_cast<X, Y>(X());
return 0;
}

View File

@@ -25,6 +25,7 @@ struct P
{
virtual ~P(){}
virtual std::string f() = 0;
std::string g() { return "P::g()"; }
};
struct PCallback : P, Callback
@@ -37,7 +38,7 @@ struct PCallback : P, Callback
}
};
struct Q : P
struct Q : virtual P
{
std::string f() { return "Q::f()"; }
};
@@ -155,6 +156,7 @@ BOOST_PYTHON_MODULE_INIT(polymorphism_ext)
;
class_<Q, bases<P> >("Q")
.def("g", &P::g) // make sure virtual inheritance doesn't interfere
;
}