Commit eda978e0 by Wenzel Jakob

support for opaque types

parent a3e34f4a
......@@ -119,6 +119,7 @@ set(PYBIND11_EXAMPLES
example/example11.cpp
example/example12.cpp
example/example13.cpp
example/example14.cpp
example/issues.cpp
)
......
......@@ -1021,7 +1021,7 @@ Partitioning code over multiple extension modules
It's straightforward to split binding code over multiple extension modules, while
referencing types that are declared elsewhere. Everything "just" works without any special
precautions. One exception to this rule occurs when wanting to extend a type declared
precautions. One exception to this rule occurs when extending a type declared
in another extension module. Recall the basic example from Section
:ref:`inheritance`.
......@@ -1063,3 +1063,55 @@ Naturally, both methods will fail when there are cyclic dependencies.
py::class_<Dog>(m, "Dog", py::base<Pet>())
.def(py::init<const std::string &>())
.def("bark", &Dog::bark);
Treating STL data structures as opaque objects
==============================================
pybind11 heavily relies on a template matching mechanism to convert parameters
and return values that are constructed from STL data types such as vectors,
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.
The fundamental limitation of this approach is the internal conversion between
Python and C++ types involves a copy operation that prevents pass-by-reference
semantics. What does this mean?
Suppose we bind the following function
.. code-block:: cpp
void append_1(std::vector<int> &v) {
v.push_back(1);
}
and call it as follows from Python:
.. code-block:: python
>>> v = [5, 6]
>>> append_1(v)
>>> print(v)
[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>``.
``opaque<T>`` disables the underlying template 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
wordy. The above function can be bound using the following wrapper code:
.. code-block:: cpp
m.def("append_1", [](py::opaque<std::vector<int>> &v) { append_1(v); });
Opaque types must also have a dedicated ``class_`` declaration to define a
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.
......@@ -22,6 +22,7 @@ void init_ex10(py::module &);
void init_ex11(py::module &);
void init_ex12(py::module &);
void init_ex13(py::module &);
void init_ex14(py::module &);
void init_issues(py::module &);
PYBIND11_PLUGIN(example) {
......@@ -40,6 +41,7 @@ PYBIND11_PLUGIN(example) {
init_ex11(m);
init_ex12(m);
init_ex13(m);
init_ex14(m);
init_issues(m);
return m.ptr();
......
/*
example/example14.cpp -- opaque types
Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#include "example.h"
#include <pybind11/stl.h>
#include <vector>
typedef std::vector<std::string> StringList;
void init_ex14(py::module &m) {
py::class_<py::opaque<StringList>>(m, "StringList")
.def(py::init<>())
.def("push_back", [](py::opaque<StringList> &l, const std::string &str) { l->push_back(str); })
.def("pop_back", [](py::opaque<StringList> &l) { l->pop_back(); })
.def("back", [](py::opaque<StringList> &l) { return l->back(); });
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;
});
}
from __future__ import print_function
import sys
sys.path.append('.')
from example import StringList, print_opaque_list
l = StringList()
l.push_back("Element 1")
l.push_back("Element 2")
print_opaque_list(l)
print("Back element is %s" % l.back())
l.pop_back()
print_opaque_list(l)
Opaque list:
Element 1
Element 2
Back element is Element 2
Opaque list:
Element 1
......@@ -17,6 +17,21 @@
#include <limits>
NAMESPACE_BEGIN(pybind11)
/// Thin wrapper type used to treat certain data types as opaque (e.g. STL vectors, etc.)
template <typename Type> class opaque {
public:
template <typename... Args> opaque(Args&&... args) : value(std::forward<Args>(args)...) { }
operator Type&() { return value; }
operator const Type&() const { return value; }
operator Type*() { return &value; }
operator const Type*() const { return &value; }
Type* operator->() { return &value; }
const Type* operator->() const { return &value; }
private:
Type value;
};
NAMESPACE_BEGIN(detail)
/// Additional type information which does not fit into the PyTypeObject
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment