support for opaque types
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f8a489c..900e26e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -119,6 +119,7 @@
example/example11.cpp
example/example12.cpp
example/example13.cpp
+ example/example14.cpp
example/issues.cpp
)
diff --git a/docs/advanced.rst b/docs/advanced.rst
index f24d3b5..74611bd 100644
--- a/docs/advanced.rst
+++ b/docs/advanced.rst
@@ -1021,7 +1021,7 @@
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 @@
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.
diff --git a/example/example.cpp b/example/example.cpp
index d84b456..a4fb4d3 100644
--- a/example/example.cpp
+++ b/example/example.cpp
@@ -22,6 +22,7 @@
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 @@
init_ex11(m);
init_ex12(m);
init_ex13(m);
+ init_ex14(m);
init_issues(m);
return m.ptr();
diff --git a/example/example14.cpp b/example/example14.cpp
new file mode 100644
index 0000000..5c6d918
--- /dev/null
+++ b/example/example14.cpp
@@ -0,0 +1,29 @@
+/*
+ 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;
+ });
+}
diff --git a/example/example14.py b/example/example14.py
new file mode 100644
index 0000000..c9c8665
--- /dev/null
+++ b/example/example14.py
@@ -0,0 +1,14 @@
+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)
diff --git a/example/example14.ref b/example/example14.ref
new file mode 100644
index 0000000..d738fef
--- /dev/null
+++ b/example/example14.ref
@@ -0,0 +1,6 @@
+Opaque list:
+ Element 1
+ Element 2
+Back element is Element 2
+Opaque list:
+ Element 1
diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h
index 89fcac1..f36b3d5 100644
--- a/include/pybind11/cast.h
+++ b/include/pybind11/cast.h
@@ -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