From d4c50383af4b1c098f02991dee2f8eeee8a15fbc Mon Sep 17 00:00:00 2001 From: Joel de Guzman Date: Fri, 23 Aug 2002 23:30:29 +0000 Subject: [PATCH] Got init<..> working [SVN r15073] --- include/boost/python/class.hpp | 10 ++- include/boost/python/init.hpp | 150 +++++++++++++++++++++++++-------- test/defaults.cpp | 16 ++++ test/defaults.py | 14 ++- 4 files changed, 153 insertions(+), 37 deletions(-) diff --git a/include/boost/python/class.hpp b/include/boost/python/class.hpp index 1e75a6f5..133b752b 100644 --- a/include/boost/python/class.hpp +++ b/include/boost/python/class.hpp @@ -31,6 +31,7 @@ # include # include # include +# include namespace boost { namespace python { @@ -165,6 +166,13 @@ class class_ : public objects::class_base return *this; } + template + self& def(init const& i, char const* doc = 0) + { + define_init(*this, i, doc); + return *this; + } + template self& def(char const* name, Arg1T arg1, Arg2T const& arg2, char const* doc = 0) { @@ -238,7 +246,7 @@ class class_ : public objects::class_base base::add_property(name, object(fget)); return *this; } - + template self& add_property(char const* name, Get const& fget, Set const& fset) { diff --git a/include/boost/python/init.hpp b/include/boost/python/init.hpp index 71a79f7a..f1c9001a 100644 --- a/include/boost/python/init.hpp +++ b/include/boost/python/init.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -26,22 +27,22 @@ #include /////////////////////////////////////////////////////////////////////////////// -#define BPL_IMPL_TEMPLATE_TYPES_WITH_DEFAULT \ +#define BOOST_PYTHON_TEMPLATE_TYPES_WITH_DEFAULT \ BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT \ ( \ BOOST_PYTHON_MAX_ARITY, \ - typename T, \ + class T, \ boost::mpl::null_argument \ ) \ -#define BPL_IMPL_TEMPLATE_TYPES \ +#define BOOST_PYTHON_TEMPLATE_TYPES \ BOOST_PP_ENUM_PARAMS \ ( \ BOOST_PYTHON_MAX_ARITY, \ - typename T \ + class T \ ) \ -#define BPL_IMPL_TEMPLATE_ARGS \ +#define BOOST_PYTHON_TEMPLATE_ARGS \ BOOST_PP_ENUM_PARAMS \ ( \ BOOST_PYTHON_MAX_ARITY, \ @@ -51,12 +52,12 @@ /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace python { -template -struct init; +template +struct init; // forward declaration /////////////////////////////////////// -template -struct optional; +template +struct optional; // forward declaration namespace detail { @@ -67,7 +68,7 @@ namespace detail { // This metaprogram checks if T is nil // /////////////////////////////////////////////////////////////////////////// - template + template struct is_nil : public boost::is_same {}; /////////////////////////////////////////////////////////////////////////// @@ -79,13 +80,13 @@ namespace detail { /////////////////////////////////////////////////////////////////////////// #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) - template + template struct is_optional { private: - template - static boost::type_traits::yes_type f(optional); + template + static boost::type_traits::yes_type f(optional); static boost::type_traits::no_type f(...); static T t(); @@ -99,14 +100,14 @@ namespace detail { /////////////////////////////////////// #else // defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) - template + template struct is_optional { BOOST_STATIC_CONSTANT(bool, value = false); }; - template - struct is_optional > { + template + struct is_optional > { BOOST_STATIC_CONSTANT(bool, value = true); }; @@ -227,10 +228,12 @@ namespace detail { }; }; - template - struct check_init_params { + struct init_base {}; - typedef boost::mpl::type_list params; + template + struct check_init_params : init_base { + + typedef boost::mpl::type_list params; BOOST_STATIC_ASSERT ( @@ -273,7 +276,7 @@ namespace detail { { }; - template + template struct count_optional_types { BOOST_STATIC_CONSTANT(int, value = @@ -295,7 +298,7 @@ namespace detail { // last in the list. // /////////////////////////////////////////////////////////////////////////////// -#define BPL_IMPL_APPEND_TO_INIT(INDEX, D) \ +#define BOOST_PYTHON_APPEND_TO_INIT(INDEX, D) \ typedef typename detail::append_to_init \ < \ BOOST_PP_CAT(l, INDEX), \ @@ -303,17 +306,19 @@ namespace detail { >::sequence BOOST_PP_CAT(l, BOOST_PP_INC(INDEX)); \ -template -struct init : detail::check_init_params { - +template +struct init : detail::check_init_params +{ typedef boost::mpl::type_list l0; BOOST_PP_REPEAT - (BOOST_PP_DEC(BOOST_PYTHON_MAX_ARITY), BPL_IMPL_APPEND_TO_INIT, 0); + (BOOST_PP_DEC(BOOST_PYTHON_MAX_ARITY), BOOST_PYTHON_APPEND_TO_INIT, 0); typedef BOOST_PP_CAT(l, BOOST_PP_DEC(BOOST_PYTHON_MAX_ARITY)) sequence; + BOOST_STATIC_CONSTANT(int, n_arguments = boost::mpl::size::value); + BOOST_STATIC_CONSTANT(int, n_defaults = - (detail::count_optional_types::value) + (detail::count_optional_types::value) ); }; @@ -324,19 +329,96 @@ struct init : detail::check_init_params { // optional::sequence returns a typelist. // /////////////////////////////////////////////////////////////////////////////// -template +template struct optional { - typedef boost::mpl::type_list sequence; + typedef boost::mpl::type_list sequence; }; -#undef BPL_IMPL_TEMPLATE_TYPES_WITH_DEFAULT -#undef BPL_IMPL_TEMPLATE_TYPES -#undef BPL_IMPL_TEMPLATE_ARGS -#undef BPL_IMPL_IS_OPTIONAL_VALUE -#undef BPL_IMPL_APPEND_TO_INIT +namespace detail { -}} // namespace boost { namespace python { + /////////////////////////////////////////////////////////////////////////////// + // + // define_class_init_helper::apply + // + // General case + // + // Accepts a class_ and an arguments list. Defines a constructor + // for the class given the arguments and recursively calls + // define_class_init_helper::apply with one less arguments (the + // rightmost argument is shaved off) + // + /////////////////////////////////////////////////////////////////////////////// + template + struct define_class_init_helper { + + template + static void apply(ClassT& cl, ArgsT const& args, char const* doc) + { + cl.def_init(args, default_call_policies(), doc); + boost::mpl::pop_back::sequence next; + define_class_init_helper::apply(cl, next, doc); + } + }; + + /////////////////////////////////////////////////////////////////////////////// + // + // define_class_init_helper<0>::apply + // + // Terminal case + // + // Accepts a class_ and an arguments list. Defines a constructor + // for the class given the arguments. + // + /////////////////////////////////////////////////////////////////////////////// + template <> + struct define_class_init_helper<0> { + + template + static void apply(ClassT& cl, ArgsT const& args, char const* doc) + { + cl.def_init(args, default_call_policies(), doc); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// define_init +// +// Accepts a class_ and an init-list. Defines a set of constructors for +// the class given the arguments. The init list (see init above) has +// n_defaults (number of default arguments and n_arguments (number of +// actual arguments). This function defines n_defaults + 1 constructors +// for the class. Each constructor after the first has one less argument +// to its right. Example: +// +// init +// +// Defines: +// +// __init__(int, char, long, double) +// __init__(int, char, long) +// __init__(int, char) +// __init__(int) +// +/////////////////////////////////////////////////////////////////////////////// +template +void +define_init(ClassT& cl, InitT const& i, char const* doc) +{ + enum { n_defaults_plus_1 = InitT::n_defaults + 1 }; + typedef typename InitT::sequence args_t; + detail::define_class_init_helper::apply(cl, args_t(), doc); +} + +}} // namespace boost::python + +#undef BOOST_PYTHON_TEMPLATE_TYPES_WITH_DEFAULT +#undef BOOST_PYTHON_TEMPLATE_TYPES +#undef BOOST_PYTHON_TEMPLATE_ARGS +#undef BOOST_PYTHON_IS_OPTIONAL_VALUE +#undef BOOST_PYTHON_APPEND_TO_INIT /////////////////////////////////////////////////////////////////////////////// #endif // INIT_JDG20020820_HPP diff --git a/test/defaults.cpp b/test/defaults.cpp index 5b162b1a..0014ab36 100644 --- a/test/defaults.cpp +++ b/test/defaults.cpp @@ -68,6 +68,12 @@ BOOST_PYTHON_FUNCTION_GENERATOR(foo_stubs, foo, 1, 4) /////////////////////////////////////////////////////////////////////////////// struct X { + X() {} + + X(int a, char b = 'D', std::string c = "constructor", double d = 0.0) + : state(format % make_tuple(a, b, c, d)) + {} + object bar(int a, char b = 'D', std::string c = "default", double d = 0.0) const { @@ -91,6 +97,14 @@ struct X { { return "list(%s); list(%s); bool(%s); " % make_tuple(a, b, c); } + + object + get_state() const + { + return state; + } + + object state; }; BOOST_PYTHON_MEM_FUN_GENERATOR(X_bar_stubs, bar, 1, 4) @@ -107,6 +121,8 @@ BOOST_PYTHON_MODULE_INIT(defaults_ext) ; class_("X") + .def(init >()) + .def("get_state", &X::get_state) .def("bar", &X::bar, X_bar_stubs()) .def("foo", (object(X::*)(std::string, bool) const)0, X_foo_2_stubs()) .def("foo", (object(X::*)(int, bool) const)0, X_foo_2_stubs()) diff --git a/test/defaults.py b/test/defaults.py index b63f972c..ac890de2 100644 --- a/test/defaults.py +++ b/test/defaults.py @@ -44,8 +44,18 @@ 'list([0, 1, 2]); list([2, 3, 4]); bool(0); ' >>> x.foo([0,1,2], [2,3,4], True) 'list([0, 1, 2]); list([2, 3, 4]); bool(1); ' ->>> - +>>> x = X(1) +>>> x.get_state() +'int(1); char(D); string(constructor); double(0.0); ' +>>> x = X(1, 'X') +>>> x.get_state() +'int(1); char(X); string(constructor); double(0.0); ' +>>> x = X(1, 'X', "Yabadabadoo") +>>> x.get_state() +'int(1); char(X); string(Yabadabadoo); double(0.0); ' +>>> x = X(1, 'X', "Phoenix", 3.65) +>>> x.get_state() +'int(1); char(X); string(Phoenix); double(3.65); ' """