Commit 44a69f78 by Ivan Smirnov Committed by Wenzel Jakob

std::experimental::optional (#475)

* Add type caster for std::experimental::optional

* Add tests for std::experimental::optional

* Support both <optional> / <experimental/optional>

* Mention std{::experimental,}::optional in the docs
parent bd560acf
......@@ -59,6 +59,7 @@ Breaking changes queued for v2.0.0 (Not yet released)
to do it manually via ``PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>)``.
* Default return values policy changes: non-static properties now use ``reference_internal``
and static properties use ``reference`` (previous default was ``automatic``, i.e. ``copy``).
* Support for ``std::experimental::optional<T>`` and ``std::optional<T>`` (C++17).
* Various minor improvements of library internals (no user-visible changes)
1.8.1 (July 12, 2016)
......
......@@ -22,6 +22,21 @@
#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
#endif
#ifdef __has_include
// std::optional
# if __has_include(<optional>)
# include <optional>
# define PYBIND11_HAS_OPTIONAL 1
# endif
// std::experimental::optional
# if __has_include(<experimental/optional>)
# include <experimental/optional>
# if __cpp_lib_experimental_optional // just in case
# define PYBIND11_HAS_EXP_OPTIONAL 1
# endif
# endif
#endif
NAMESPACE_BEGIN(pybind11)
NAMESPACE_BEGIN(detail)
......@@ -183,6 +198,47 @@ template <typename Key, typename Value, typename Compare, typename Alloc> struct
template <typename Key, typename Value, typename Hash, typename Equal, typename Alloc> struct type_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>>
: map_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>, Key, Value> { };
// This type caster is intended to be used for std::optional and std::experimental::optional
template<typename T> struct optional_caster {
using value_type = typename intrinsic_type<typename T::value_type>::type;
using caster_type = type_caster<value_type>;
static handle cast(const T& src, return_value_policy policy, handle parent) {
if (!src)
return none();
return caster_type::cast(*src, policy, parent);
}
bool load(handle src, bool convert) {
if (!src) {
return false;
} else if (src.is_none()) {
value = {}; // nullopt
return true;
} else if (!inner.load(src, convert)) {
return false;
} else {
value.emplace(static_cast<const value_type&>(inner));
return true;
}
}
PYBIND11_TYPE_CASTER(T, _("Optional[") + caster_type::name() + _("]"));
private:
caster_type inner;
};
#if PYBIND11_HAS_OPTIONAL
template<typename T> struct type_caster<std::optional<T>>
: public optional_caster<std::optional<T>> {};
#endif
#if PYBIND11_HAS_EXP_OPTIONAL
template<typename T> struct type_caster<std::experimental::optional<T>>
: public optional_caster<std::experimental::optional<T>> {};
#endif
NAMESPACE_END(detail)
inline std::ostream &operator<<(std::ostream &os, const handle &obj) {
......
......@@ -289,4 +289,18 @@ test_initializer python_types([](py::module &m) {
return d;
});
// this only tests std::experimental::optional for now
bool has_optional = false;
#ifdef PYBIND11_HAS_EXP_OPTIONAL
has_optional = true;
using opt_int = std::experimental::optional<int>;
m.def("double_or_zero", [](const opt_int& x) -> int {
return x.value_or(0) * 2;
});
m.def("half_or_none", [](int x) -> opt_int {
return x ? opt_int(x / 2) : opt_int();
});
#endif
m.attr("has_optional") = py::cast(has_optional);
});
import pytest
from pybind11_tests import ExamplePythonTypes, ConstructorStats
from pybind11_tests import ExamplePythonTypes, ConstructorStats, has_optional
def test_static():
......@@ -295,3 +295,16 @@ def test_accessors():
assert d["set"] == 1
assert d["deferred_set"] == 1
assert d["var"] == 99
@pytest.mark.skipif(not has_optional, reason='no <experimental/optional>')
def test_optional():
from pybind11_tests import double_or_zero, half_or_none
assert double_or_zero(None) == 0
assert double_or_zero(42) == 84
pytest.raises(TypeError, double_or_zero, 'foo')
assert half_or_none(0) is None
assert half_or_none(42) == 21
pytest.raises(TypeError, half_or_none, 'foo')
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