Skip to content

Commit d4c5038

Browse files
committed
Got init<..> working
[SVN r15073]
1 parent 1ee7bd2 commit d4c5038

File tree

4 files changed

+153
-37
lines changed

4 files changed

+153
-37
lines changed

include/boost/python/class.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
# include <boost/python/detail/force_instantiate.hpp>
3232
# include <boost/python/detail/defaults_def.hpp>
3333
# include <boost/python/signature.hpp>
34+
# include <boost/python/init.hpp>
3435

3536
namespace boost { namespace python {
3637

@@ -165,6 +166,13 @@ class class_ : public objects::class_base
165166
return *this;
166167
}
167168

169+
template <BOOST_PP_ENUM_PARAMS(BOOST_PYTHON_MAX_ARITY, class T)>
170+
self& def(init<BOOST_PP_ENUM_PARAMS(BOOST_PYTHON_MAX_ARITY, T)> const& i, char const* doc = 0)
171+
{
172+
define_init(*this, i, doc);
173+
return *this;
174+
}
175+
168176
template <class Arg1T, class Arg2T>
169177
self& def(char const* name, Arg1T arg1, Arg2T const& arg2, char const* doc = 0)
170178
{
@@ -238,7 +246,7 @@ class class_ : public objects::class_base
238246
base::add_property(name, object(fget));
239247
return *this;
240248
}
241-
249+
242250
template <class Get, class Set>
243251
self& add_property(char const* name, Get const& fget, Set const& fset)
244252
{

include/boost/python/init.hpp

Lines changed: 116 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <boost/mpl/at.hpp>
1717
#include <boost/mpl/size.hpp>
1818
#include <boost/mpl/pop_front.hpp>
19+
#include <boost/mpl/pop_back.hpp>
1920

2021
#include <boost/static_assert.hpp>
2122
#include <boost/preprocessor/enum_params_with_a_default.hpp>
@@ -26,22 +27,22 @@
2627
#include <boost/preprocessor/dec.hpp>
2728

2829
///////////////////////////////////////////////////////////////////////////////
29-
#define BPL_IMPL_TEMPLATE_TYPES_WITH_DEFAULT \
30+
#define BOOST_PYTHON_TEMPLATE_TYPES_WITH_DEFAULT \
3031
BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT \
3132
( \
3233
BOOST_PYTHON_MAX_ARITY, \
33-
typename T, \
34+
class T, \
3435
boost::mpl::null_argument \
3536
) \
3637

37-
#define BPL_IMPL_TEMPLATE_TYPES \
38+
#define BOOST_PYTHON_TEMPLATE_TYPES \
3839
BOOST_PP_ENUM_PARAMS \
3940
( \
4041
BOOST_PYTHON_MAX_ARITY, \
41-
typename T \
42+
class T \
4243
) \
4344

44-
#define BPL_IMPL_TEMPLATE_ARGS \
45+
#define BOOST_PYTHON_TEMPLATE_ARGS \
4546
BOOST_PP_ENUM_PARAMS \
4647
( \
4748
BOOST_PYTHON_MAX_ARITY, \
@@ -51,12 +52,12 @@
5152
///////////////////////////////////////////////////////////////////////////////
5253
namespace boost { namespace python {
5354

54-
template <BPL_IMPL_TEMPLATE_TYPES_WITH_DEFAULT>
55-
struct init;
55+
template <BOOST_PYTHON_TEMPLATE_TYPES_WITH_DEFAULT>
56+
struct init; // forward declaration
5657

5758
///////////////////////////////////////
58-
template <BPL_IMPL_TEMPLATE_TYPES_WITH_DEFAULT>
59-
struct optional;
59+
template <BOOST_PYTHON_TEMPLATE_TYPES_WITH_DEFAULT>
60+
struct optional; // forward declaration
6061

6162
namespace detail {
6263

@@ -67,7 +68,7 @@ namespace detail {
6768
// This metaprogram checks if T is nil
6869
//
6970
///////////////////////////////////////////////////////////////////////////
70-
template <typename T>
71+
template <class T>
7172
struct is_nil : public boost::is_same<T, boost::mpl::null_argument> {};
7273

7374
///////////////////////////////////////////////////////////////////////////
@@ -79,13 +80,13 @@ namespace detail {
7980
///////////////////////////////////////////////////////////////////////////
8081
#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
8182

82-
template <typename T>
83+
template <class T>
8384
struct is_optional {
8485

8586
private:
8687

87-
template <BPL_IMPL_TEMPLATE_TYPES>
88-
static boost::type_traits::yes_type f(optional<BPL_IMPL_TEMPLATE_ARGS>);
88+
template <BOOST_PYTHON_TEMPLATE_TYPES>
89+
static boost::type_traits::yes_type f(optional<BOOST_PYTHON_TEMPLATE_ARGS>);
8990
static boost::type_traits::no_type f(...);
9091
static T t();
9192

@@ -99,14 +100,14 @@ namespace detail {
99100
///////////////////////////////////////
100101
#else // defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
101102

102-
template <typename T>
103+
template <class T>
103104
struct is_optional {
104105

105106
BOOST_STATIC_CONSTANT(bool, value = false);
106107
};
107108

108-
template <BPL_IMPL_TEMPLATE_TYPES>
109-
struct is_optional<optional<BPL_IMPL_TEMPLATE_ARGS> > {
109+
template <BOOST_PYTHON_TEMPLATE_TYPES>
110+
struct is_optional<optional<BOOST_PYTHON_TEMPLATE_ARGS> > {
110111

111112
BOOST_STATIC_CONSTANT(bool, value = true);
112113
};
@@ -227,10 +228,12 @@ namespace detail {
227228
};
228229
};
229230

230-
template <BPL_IMPL_TEMPLATE_TYPES>
231-
struct check_init_params {
231+
struct init_base {};
232+
233+
template <BOOST_PYTHON_TEMPLATE_TYPES>
234+
struct check_init_params : init_base {
232235

233-
typedef boost::mpl::type_list<BPL_IMPL_TEMPLATE_ARGS> params;
236+
typedef boost::mpl::type_list<BOOST_PYTHON_TEMPLATE_ARGS> params;
234237

235238
BOOST_STATIC_ASSERT
236239
(
@@ -273,7 +276,7 @@ namespace detail {
273276
{
274277
};
275278

276-
template <BPL_IMPL_TEMPLATE_TYPES>
279+
template <BOOST_PYTHON_TEMPLATE_TYPES>
277280
struct count_optional_types {
278281

279282
BOOST_STATIC_CONSTANT(int, value =
@@ -295,25 +298,27 @@ namespace detail {
295298
// last in the list.
296299
//
297300
///////////////////////////////////////////////////////////////////////////////
298-
#define BPL_IMPL_APPEND_TO_INIT(INDEX, D) \
301+
#define BOOST_PYTHON_APPEND_TO_INIT(INDEX, D) \
299302
typedef typename detail::append_to_init \
300303
< \
301304
BOOST_PP_CAT(l, INDEX), \
302305
BOOST_PP_CAT(T, BOOST_PP_INC(INDEX)) \
303306
>::sequence BOOST_PP_CAT(l, BOOST_PP_INC(INDEX)); \
304307

305308

306-
template <BPL_IMPL_TEMPLATE_TYPES>
307-
struct init : detail::check_init_params<BPL_IMPL_TEMPLATE_ARGS> {
308-
309+
template <BOOST_PYTHON_TEMPLATE_TYPES>
310+
struct init : detail::check_init_params<BOOST_PYTHON_TEMPLATE_ARGS>
311+
{
309312
typedef boost::mpl::type_list<T0> l0;
310313
BOOST_PP_REPEAT
311-
(BOOST_PP_DEC(BOOST_PYTHON_MAX_ARITY), BPL_IMPL_APPEND_TO_INIT, 0);
314+
(BOOST_PP_DEC(BOOST_PYTHON_MAX_ARITY), BOOST_PYTHON_APPEND_TO_INIT, 0);
312315

313316
typedef BOOST_PP_CAT(l, BOOST_PP_DEC(BOOST_PYTHON_MAX_ARITY)) sequence;
314317

318+
BOOST_STATIC_CONSTANT(int, n_arguments = boost::mpl::size<sequence>::value);
319+
315320
BOOST_STATIC_CONSTANT(int, n_defaults =
316-
(detail::count_optional_types<BPL_IMPL_TEMPLATE_ARGS>::value)
321+
(detail::count_optional_types<BOOST_PYTHON_TEMPLATE_ARGS>::value)
317322
);
318323
};
319324

@@ -324,19 +329,96 @@ struct init : detail::check_init_params<BPL_IMPL_TEMPLATE_ARGS> {
324329
// optional<T0...TN>::sequence returns a typelist.
325330
//
326331
///////////////////////////////////////////////////////////////////////////////
327-
template <BPL_IMPL_TEMPLATE_TYPES>
332+
template <BOOST_PYTHON_TEMPLATE_TYPES>
328333
struct optional {
329334

330-
typedef boost::mpl::type_list<BPL_IMPL_TEMPLATE_ARGS> sequence;
335+
typedef boost::mpl::type_list<BOOST_PYTHON_TEMPLATE_ARGS> sequence;
331336
};
332337

333-
#undef BPL_IMPL_TEMPLATE_TYPES_WITH_DEFAULT
334-
#undef BPL_IMPL_TEMPLATE_TYPES
335-
#undef BPL_IMPL_TEMPLATE_ARGS
336-
#undef BPL_IMPL_IS_OPTIONAL_VALUE
337-
#undef BPL_IMPL_APPEND_TO_INIT
338+
namespace detail {
339+
340+
///////////////////////////////////////////////////////////////////////////////
341+
//
342+
// define_class_init_helper<N>::apply
343+
//
344+
// General case
345+
//
346+
// Accepts a class_ and an arguments list. Defines a constructor
347+
// for the class given the arguments and recursively calls
348+
// define_class_init_helper<N-1>::apply with one less arguments (the
349+
// rightmost argument is shaved off)
350+
//
351+
///////////////////////////////////////////////////////////////////////////////
352+
template <int N>
353+
struct define_class_init_helper {
354+
355+
template <class ClassT, class ArgsT>
356+
static void apply(ClassT& cl, ArgsT const& args, char const* doc)
357+
{
358+
cl.def_init(args, default_call_policies(), doc);
359+
boost::mpl::pop_back<ArgsT>::sequence next;
360+
define_class_init_helper<N-1>::apply(cl, next, doc);
361+
}
362+
};
363+
364+
///////////////////////////////////////////////////////////////////////////////
365+
//
366+
// define_class_init_helper<0>::apply
367+
//
368+
// Terminal case
369+
//
370+
// Accepts a class_ and an arguments list. Defines a constructor
371+
// for the class given the arguments.
372+
//
373+
///////////////////////////////////////////////////////////////////////////////
374+
template <>
375+
struct define_class_init_helper<0> {
376+
377+
template <class ClassT, class ArgsT>
378+
static void apply(ClassT& cl, ArgsT const& args, char const* doc)
379+
{
380+
cl.def_init(args, default_call_policies(), doc);
381+
}
382+
};
383+
}
338384

339-
}} // namespace boost { namespace python {
385+
///////////////////////////////////////////////////////////////////////////////
386+
//
387+
// define_init
388+
//
389+
// Accepts a class_ and an init-list. Defines a set of constructors for
390+
// the class given the arguments. The init list (see init above) has
391+
// n_defaults (number of default arguments and n_arguments (number of
392+
// actual arguments). This function defines n_defaults + 1 constructors
393+
// for the class. Each constructor after the first has one less argument
394+
// to its right. Example:
395+
//
396+
// init<int, default<char, long, double>
397+
//
398+
// Defines:
399+
//
400+
// __init__(int, char, long, double)
401+
// __init__(int, char, long)
402+
// __init__(int, char)
403+
// __init__(int)
404+
//
405+
///////////////////////////////////////////////////////////////////////////////
406+
template <class ClassT, class InitT>
407+
void
408+
define_init(ClassT& cl, InitT const& i, char const* doc)
409+
{
410+
enum { n_defaults_plus_1 = InitT::n_defaults + 1 };
411+
typedef typename InitT::sequence args_t;
412+
detail::define_class_init_helper<n_defaults_plus_1>::apply(cl, args_t(), doc);
413+
}
414+
415+
}} // namespace boost::python
416+
417+
#undef BOOST_PYTHON_TEMPLATE_TYPES_WITH_DEFAULT
418+
#undef BOOST_PYTHON_TEMPLATE_TYPES
419+
#undef BOOST_PYTHON_TEMPLATE_ARGS
420+
#undef BOOST_PYTHON_IS_OPTIONAL_VALUE
421+
#undef BOOST_PYTHON_APPEND_TO_INIT
340422

341423
///////////////////////////////////////////////////////////////////////////////
342424
#endif // INIT_JDG20020820_HPP

test/defaults.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ BOOST_PYTHON_FUNCTION_GENERATOR(foo_stubs, foo, 1, 4)
6868
///////////////////////////////////////////////////////////////////////////////
6969
struct X {
7070

71+
X() {}
72+
73+
X(int a, char b = 'D', std::string c = "constructor", double d = 0.0)
74+
: state(format % make_tuple(a, b, c, d))
75+
{}
76+
7177
object
7278
bar(int a, char b = 'D', std::string c = "default", double d = 0.0) const
7379
{
@@ -91,6 +97,14 @@ struct X {
9197
{
9298
return "list(%s); list(%s); bool(%s); " % make_tuple(a, b, c);
9399
}
100+
101+
object
102+
get_state() const
103+
{
104+
return state;
105+
}
106+
107+
object state;
94108
};
95109

96110
BOOST_PYTHON_MEM_FUN_GENERATOR(X_bar_stubs, bar, 1, 4)
@@ -107,6 +121,8 @@ BOOST_PYTHON_MODULE_INIT(defaults_ext)
107121
;
108122

109123
class_<X>("X")
124+
.def(init<int, optional<char, std::string, double> >())
125+
.def("get_state", &X::get_state)
110126
.def("bar", &X::bar, X_bar_stubs())
111127
.def("foo", (object(X::*)(std::string, bool) const)0, X_foo_2_stubs())
112128
.def("foo", (object(X::*)(int, bool) const)0, X_foo_2_stubs())

test/defaults.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,18 @@
4444
'list([0, 1, 2]); list([2, 3, 4]); bool(0); '
4545
>>> x.foo([0,1,2], [2,3,4], True)
4646
'list([0, 1, 2]); list([2, 3, 4]); bool(1); '
47-
>>>
48-
47+
>>> x = X(1)
48+
>>> x.get_state()
49+
'int(1); char(D); string(constructor); double(0.0); '
50+
>>> x = X(1, 'X')
51+
>>> x.get_state()
52+
'int(1); char(X); string(constructor); double(0.0); '
53+
>>> x = X(1, 'X', "Yabadabadoo")
54+
>>> x.get_state()
55+
'int(1); char(X); string(Yabadabadoo); double(0.0); '
56+
>>> x = X(1, 'X', "Phoenix", 3.65)
57+
>>> x.get_state()
58+
'int(1); char(X); string(Phoenix); double(3.65); '
4959
5060
5161
"""

0 commit comments

Comments
 (0)