opaque<> clarifications

This commit is contained in:
Wenzel Jakob 2016-04-22 16:52:15 +02:00
parent 5a2924275c
commit 0871228f42
4 changed files with 78 additions and 14 deletions

View File

@ -1145,8 +1145,8 @@ linked lists, hash tables, etc. This even works in a recursive manner, for
instance to deal with lists of hash maps of pairs of elementary and custom
types, etc.
A fundamental limitation of this approach is that the internal conversion
between Python and C++ types involves a copy operation that prevents
However, a fundamental limitation of this approach is that internal conversions
between Python and C++ types involve a copy operation that prevents
pass-by-reference semantics. What does this mean?
Suppose we bind the following function
@ -1167,10 +1167,41 @@ and call it as follows from Python:
[5, 6]
As you can see, when passing STL data structures by reference, modifications
are not propagated back the Python side. To deal with situations where this
desirable, pybind11 contains a simple template wrapper class named ``opaque<T>``.
are not propagated back the Python side. A similar situation arises when
exposing STL data structures using the ``def_readwrite`` or ``def_readonly``
functions:
``opaque<T>`` disables the underlying template machinery for
.. code-block:: cpp
/* ... definition ... */
class MyClass {
std::vector<int> contents;
};
/* ... binding code ... */
py::class_<MyClass>(m, "MyClass")
.def(py::init<>)
.def_readwrite("contents", &MyClass::contents);
In this case, properties can be read and written in their entirety. However, an
``append`` operaton involving such a list type has no effect:
.. code-block:: python
>>> m = MyClass()
>>> m.contents = [5, 6]
>>> print(m.contents)
[5, 6]
>>> m.contents.append(7)
>>> print(m.contents)
[5, 6]
To deal with both of the above situations, pybind11 contains a simple template
wrapper class named ``opaque<T>``.
``opaque<T>`` disables pybind11's template-based conversion machinery for
``T`` and can be used to treat STL types as opaque objects, whose contents are
never inspected or extracted (thus, they can be passed by reference).
The downside of this approach is that it the binding code becomes a bit more
@ -1186,7 +1217,8 @@ set of admissible operations.
.. seealso::
The file :file:`example/example14.cpp` contains a complete example that
demonstrates how to create opaque types using pybind11 in more detail.
demonstrates how to create and expose opaque types using pybind11 in more
detail.
Pickling support
================

View File

@ -13,6 +13,11 @@
typedef std::vector<std::string> StringList;
class ClassWithSTLVecProperty {
public:
StringList stringList;
};
void init_ex14(py::module &m) {
py::class_<py::opaque<StringList>>(m, "StringList")
.def(py::init<>())
@ -20,11 +25,24 @@ void init_ex14(py::module &m) {
.def("pop_back", [](py::opaque<StringList> &l) { l->pop_back(); })
.def("back", [](py::opaque<StringList> &l) { return l->back(); });
py::class_<ClassWithSTLVecProperty>(m, "ClassWithSTLVecProperty")
.def(py::init<>())
/* Need to cast properties to opaque types to avoid pybind11-internal
STL conversion code from becoming active */
.def_readwrite("stringList", (py::opaque<StringList> ClassWithSTLVecProperty:: *)
&ClassWithSTLVecProperty::stringList);
m.def("print_opaque_list", [](py::opaque<StringList> &_l) {
StringList &l = _l;
std::cout << "Opaque list: " << std::endl;
for (auto entry : l)
std::cout << " " << entry << std::endl;
std::cout << "Opaque list: [";
bool first = true;
for (auto entry : l) {
if (!first)
std::cout << ", ";
std::cout << entry;
first = false;
}
std::cout << "]" << std::endl;
});
m.def("return_void_ptr", []() { return (void *) 1234; });

View File

@ -4,10 +4,13 @@ import sys
sys.path.append('.')
from example import StringList, print_opaque_list
from example import ClassWithSTLVecProperty
from example import return_void_ptr, print_void_ptr
from example import return_null_str, print_null_str
from example import return_unique_ptr
#####
l = StringList()
l.push_back("Element 1")
l.push_back("Element 2")
@ -16,9 +19,21 @@ print("Back element is %s" % l.back())
l.pop_back()
print_opaque_list(l)
#####
cvp = ClassWithSTLVecProperty()
print_opaque_list(cvp.stringList)
cvp.stringList = l
cvp.stringList.push_back("Element 3")
print_opaque_list(cvp.stringList)
#####
print_void_ptr(return_void_ptr())
print(return_null_str())
print_null_str(return_null_str())
#####
print(return_unique_ptr())

View File

@ -1,9 +1,8 @@
Opaque list:
Element 1
Element 2
Opaque list: [Element 1, Element 2]
Back element is Element 2
Opaque list:
Element 1
Opaque list: [Element 1]
Opaque list: []
Opaque list: [Element 1, Element 3]
Got void ptr : 1234
None
Got null str : 0