Add support for non-converting arguments
This adds support for controlling the `convert` flag of arguments
through the py::arg annotation. This then allows arguments to be
flagged as non-converting, which the type_caster is able to use to
request different behaviour.
Currently, AFAICS `convert` is only used for type converters of regular
pybind11-registered types; all of the other core type_casters ignore it.
We can, however, repurpose it to control internal conversion of
converters like Eigen and `array`: most usefully to give callers a way
to disable the conversion that would otherwise occur when a
`Eigen::Ref<const Eigen::Matrix>` argument is passed a numpy array that
requires conversion (either because it has an incompatible stride or the
wrong dtype).
Specifying a noconvert looks like one of these:
m.def("f1", &f, "a"_a.noconvert() = "default"); // Named, default, noconvert
m.def("f2", &f, "a"_a.noconvert()); // Named, no default, no converting
m.def("f3", &f, py::arg().noconvert()); // Unnamed, no default, no converting
(The last part--being able to declare a py::arg without a name--is new:
previous py::arg() only accepted named keyword arguments).
Such an non-convert argument is then passed `convert = false` by the
type caster when loading the argument. Whether this has an effect is up
to the type caster itself, but as mentioned above, this would be
extremely helpful for the Eigen support to give a nicer way to specify
a "no-copy" mode than the custom wrapper in the current PR, and
moreover isn't an Eigen-specific hack.
diff --git a/docs/advanced/classes.rst b/docs/advanced/classes.rst
index 9d17364..e0463b4 100644
--- a/docs/advanced/classes.rst
+++ b/docs/advanced/classes.rst
@@ -388,6 +388,8 @@
py::class_<MyClass, std::unique_ptr<MyClass, py::nodelete>>(m, "MyClass")
.def(py::init<>())
+.. _implicit_conversions:
+
Implicit conversions
====================
diff --git a/docs/advanced/functions.rst b/docs/advanced/functions.rst
index 7ffdfaa..e67d7bc 100644
--- a/docs/advanced/functions.rst
+++ b/docs/advanced/functions.rst
@@ -318,3 +318,57 @@
py::class_<MyClass>("MyClass")
.def("myFunction", py::arg("arg") = (SomeType *) nullptr);
+
+Non-converting arguments
+========================
+
+Certain argument types may support conversion from one type to another. Some
+examples of conversions are:
+
+* :ref:`implicit_conversions` declared using ``py::implicitly_convertible<A,B>()``
+* Calling a method accepting a double with an integer argument
+* Calling a ``std::complex<float>`` argument with a non-complex python type
+ (for example, with a float). (Requires the optional ``pybind11/complex.h``
+ header).
+* Calling a function taking an Eigen matrix reference with a numpy array of the
+ wrong type or of an incompatible data layout. (Requires the optional
+ ``pybind11/eigen.h`` header).
+
+This behaviour is sometimes undesirable: the binding code may prefer to raise
+an error rather than convert the argument. This behaviour can be obtained
+through ``py::arg`` by calling the ``.noconvert()`` method of the ``py::arg``
+object, such as:
+
+.. code-block:: cpp
+
+ m.def("floats_only", [](double f) { return 0.5 * f; }, py::arg("f").noconvert());
+ m.def("floats_preferred", [](double f) { return 0.5 * f; }, py::arg("f"));
+
+Attempting the call the second function (the one without ``.noconvert()``) with
+an integer will succeed, but attempting to call the ``.noconvert()`` version
+will fail with a ``TypeError``:
+
+.. code-block:: pycon
+
+ >>> floats_preferred(4)
+ 2.0
+ >>> floats_only(4)
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ TypeError: floats_only(): incompatible function arguments. The following argument types are supported:
+ 1. (f: float) -> float
+
+ Invoked with: 4
+
+You may, of course, combine this with the :var:`_a` shorthand notation (see
+:ref:`keyword_args`) and/or :ref:`default_args`. It is also permitted to omit
+the argument name by using the ``py::arg()`` constructor without an argument
+name, i.e. by specifying ``py::arg().noconvert()``.
+
+.. note::
+
+ When specifying ``py::arg`` options it is necessary to provide the same
+ number of options as the bound function has arguments. Thus if you want to
+ enable no-convert behaviour for just one of several arguments, you will
+ need to specify a ``py::arg()`` annotation for each argument with the
+ no-convert argument modified to ``py::arg().noconvert()``.