tutorial.qbk
来自「Boost provides free peer-reviewed portab」· QBK 代码 · 共 1,973 行 · 第 1/5 页
QBK
1,973 行
def("f", f, return_internal_reference<1, with_custodian_and_ward<1, 2> >());What are the [^1] and [^2] parameters, you ask? return_internal_reference<1Informs Boost.Python that the first argument, in our case [^Y& y], is theowner of the returned reference: [^X&]. The "[^1]" simply specifies thefirst argument. In short: "return an internal reference [^X&] owned by the1st argument [^Y& y]". with_custodian_and_ward<1, 2>Informs Boost.Python that the lifetime of the argument indicated by ward(i.e. the 2nd argument: [^Z* z]) is dependent on the lifetime of theargument indicated by custodian (i.e. the 1st argument: [^Y& y]).It is also important to note that we have defined two policies above. Twoor more policies can be composed by chaining. Here's the general syntax: policy1<args..., policy2<args..., policy3<args...> > >Here is the list of predefined call policies. A complete reference detailingthese can be found [@../../../v2/reference.html#models_of_call_policies here].* [*with_custodian_and_ward]: Ties lifetimes of the arguments* [*with_custodian_and_ward_postcall]: Ties lifetimes of the arguments and results* [*return_internal_reference]: Ties lifetime of one argument to that of result* [*return_value_policy<T> with T one of:] * [*reference_existing_object]: naive (dangerous) approach * [*copy_const_reference]: Boost.Python v1 approach * [*copy_non_const_reference]: * [*manage_new_object]: Adopt a pointer and hold the instance[blurb :-) [*Remember the Zen, Luke:]"Explicit is better than implicit""In the face of ambiguity, refuse the temptation to guess"][endsect][section Overloading]The following illustrates a scheme for manually wrapping an overloadedmember functions. Of course, the same technique can be applied to wrappingoverloaded non-member functions.We have here our C++ class: struct X { bool f(int a) { return true; } bool f(int a, double b) { return true; } bool f(int a, double b, char c) { return true; } int f(int a, int b, int c) { return a + b + c; }; };Class X has 4 overloaded functions. We will start by introducing somemember function pointer variables: bool (X::*fx1)(int) = &X::f; bool (X::*fx2)(int, double) = &X::f; bool (X::*fx3)(int, double, char)= &X::f; int (X::*fx4)(int, int, int) = &X::f;With these in hand, we can proceed to define and wrap this for Python: .def("f", fx1) .def("f", fx2) .def("f", fx3) .def("f", fx4)[endsect][section Default Arguments]Boost.Python wraps (member) function pointers. Unfortunately, C++ functionpointers carry no default argument info. Take a function [^f] with defaultarguments: int f(int, double = 3.14, char const* = "hello");But the type of a pointer to the function [^f] has no informationabout its default arguments: int(*g)(int,double,char const*) = f; // defaults lost!When we pass this function pointer to the [^def] function, there is no wayto retrieve the default arguments: def("f", f); // defaults lost!Because of this, when wrapping C++ code, we had to resort to manualwrapping as outlined in the [link python.overloading previous section], orwriting thin wrappers: // write "thin wrappers" int f1(int x) { f(x); } int f2(int x, double y) { f(x,y); } /*...*/ // in module init def("f", f); // all arguments def("f", f2); // two arguments def("f", f1); // one argumentWhen you want to wrap functions (or member functions) that either:* have default arguments, or* are overloaded with a common sequence of initial arguments[h2 BOOST_PYTHON_FUNCTION_OVERLOADS]Boost.Python now has a way to make it easier. For instance, given a function: int foo(int a, char b = 1, unsigned c = 2, double d = 3) { /*...*/ }The macro invocation: BOOST_PYTHON_FUNCTION_OVERLOADS(foo_overloads, foo, 1, 4)will automatically create the thin wrappers for us. This macro will createa class [^foo_overloads] that can be passed on to [^def(...)]. The thirdand fourth macro argument are the minimum arguments and maximum arguments,respectively. In our [^foo] function the minimum number of arguments is 1and the maximum number of arguments is 4. The [^def(...)] function willautomatically add all the foo variants for us: def("foo", foo, foo_overloads());[h2 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS]Objects here, objects there, objects here there everywhere. More frequentlythan anything else, we need to expose member functions of our classes toPython. Then again, we have the same inconveniences as before when defaultarguments or overloads with a common sequence of initial arguments comeinto play. Another macro is provided to make this a breeze.Like [^BOOST_PYTHON_FUNCTION_OVERLOADS],[^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] may be used to automatically createthe thin wrappers for wrapping member functions. Let's have an example: struct george { void wack_em(int a, int b = 0, char c = 'x') { /*...*/ } };The macro invocation: BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(george_overloads, wack_em, 1, 3)will generate a set of thin wrappers for george's [^wack_em] member functionaccepting a minimum of 1 and a maximum of 3 arguments (i.e. the third andfourth macro argument). The thin wrappers are all enclosed in a class named[^george_overloads] that can then be used as an argument to [^def(...)]: .def("wack_em", &george::wack_em, george_overloads());See the [@../../../v2/overloads.html#BOOST_PYTHON_FUNCTION_OVERLOADS-spec overloads reference]for details.[h2 init and optional]A similar facility is provided for class constructors, again, withdefault arguments or a sequence of overloads. Remember [^init<...>]? For example,given a class X with a constructor: struct X { X(int a, char b = 'D', std::string c = "constructor", double d = 0.0); /*...*/ }You can easily add this constructor to Boost.Python in one shot: .def(init<int, optional<char, std::string, double> >())Notice the use of [^init<...>] and [^optional<...>] to signify the default(optional arguments).[endsect][section Auto-Overloading]It was mentioned in passing in the previous section that[^BOOST_PYTHON_FUNCTION_OVERLOADS] and [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS]can also be used for overloaded functions and member functions with acommon sequence of initial arguments. Here is an example: void foo() { /*...*/ } void foo(bool a) { /*...*/ } void foo(bool a, int b) { /*...*/ } void foo(bool a, int b, char c) { /*...*/ }Like in the previous section, we can generate thin wrappers for theseoverloaded functions in one-shot: BOOST_PYTHON_FUNCTION_OVERLOADS(foo_overloads, foo, 0, 3)Then... .def("foo", (void(*)(bool, int, char))0, foo_overloads());Notice though that we have a situation now where we have a minimum of zero(0) arguments and a maximum of 3 arguments.[h2 Manual Wrapping]It is important to emphasize however that [*the overloaded functions musthave a common sequence of initial arguments]. Otherwise, our scheme abovewill not work. If this is not the case, we have to wrap our functions[link python.overloading manually].Actually, we can mix and match manual wrapping of overloaded functions andautomatic wrapping through [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] andits sister, [^BOOST_PYTHON_FUNCTION_OVERLOADS]. Following up on our examplepresented in the section [link python.overloading on overloading], since thefirst 4 overload functins have a common sequence of initial arguments, wecan use [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] to automatically wrap thefirst three of the [^def]s and manually wrap just the last. Here'show we'll do this: BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(xf_overloads, f, 1, 4)Create a member function pointers as above for both X::f overloads: bool (X::*fx1)(int, double, char) = &X::f; int (X::*fx2)(int, int, int) = &X::f;Then... .def("f", fx1, xf_overloads()); .def("f", fx2)[endsect][endsect] [/ Functions ][section:object Object Interface]Python is dynamically typed, unlike C++ which is statically typed. Pythonvariables may hold an integer, a float, list, dict, tuple, str, long etc.,among other things. In the viewpoint of Boost.Python and C++, thesePythonic variables are just instances of class [^object]. We will see inthis chapter how to deal with Python objects.As mentioned, one of the goals of Boost.Python is to provide abidirectional mapping between C++ and Python while maintaining the Pythonfeel. Boost.Python C++ [^object]s are as close as possible to Python. Thisshould minimize the learning curve significantly.[$images/python.png][section Basic Interface]Class [^object] wraps [^PyObject*]. All the intricacies of dealing with[^PyObject]s such as managing reference counting are handled by the[^object] class. C++ object interoperability is seamless. Boost.Python C++[^object]s can in fact be explicitly constructed from any C++ object.To illustrate, this Python code snippet:[python] def f(x, y): if (y == 'foo'): x[3:7] = 'bar' else: x.items += y(3, x) return x def getfunc(): return f;Can be rewritten in C++ using Boost.Python facilities this way:[c++] object f(object x, object y) { if (y == "foo") x.slice(3,7) = "bar"; else x.attr("items") += y(3, x); return x; } object getfunc() { return object(f); }Apart from cosmetic differences due to the fact that we are writing thecode in C++, the look and feel should be immediately apparent to the Pythoncoder.[endsect][section Derived Object types]Boost.Python comes with a set of derived [^object] types corresponding tothat of Python's:* list* dict* tuple* str* long_* enumThese derived [^object] types act like real Python types. For instance: str(1) ==> "1"Wherever appropriate, a particular derived [^object] has correspondingPython type's methods. For instance, [^dict] has a [^keys()] method: d.keys()[^make_tuple] is provided for declaring ['tuple literals]. Example: make_tuple(123, 'D', "Hello, World", 0.0);In C++, when Boost.Python [^object]s are used as arguments to functions,subtype matching is required. For example, when a function [^f], asdeclared below, is wrapped, it will only accept instances of Python's[^str] type and subtypes. void f(str name) { object n2 = name.attr("upper")(); // NAME = name.upper() str NAME = name.upper(); // better object msg = "%s is bigger than %s" % make_tuple(NAME,name); }In finer detail: str NAME = name.upper();Illustrates that we provide versions of the str type's methods as C++member functions. object msg = "%s is bigger than %s" % make_tuple(NAME,name);Demonstrates that you can write the C++ equivalent of [^"format" % x,y,z]in Python, which is useful since there's no easy way to do that in std C++.[blurb __alert__ [*Beware] the common pitfall of forgetting that the constructors of most of Python's mutable types make copies, just as in Python.]Python:[python] >>> d = dict(x.__dict__) # copies x.__dict__ >>> d['whatever'] = 3 # modifies the copy
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?