Add type casters for nullopt_t, fix none refcount (#499)

* Incref returned None in std::optional type caster

* Add type casters for nullopt_t

* Add a test for nullopt_t
This commit is contained in:
Ivan Smirnov 2016-11-15 12:00:38 +00:00 committed by Wenzel Jakob
parent 9a110e6da8
commit 425b4970b2
4 changed files with 21 additions and 5 deletions

View File

@ -512,15 +512,17 @@ public:
PYBIND11_TYPE_CASTER(T, _<std::is_integral<T>::value>("int", "float"));
};
template <> class type_caster<void_type> {
template<typename T> struct void_caster {
public:
bool load(handle, bool) { return false; }
static handle cast(void_type, return_value_policy /* policy */, handle /* parent */) {
static handle cast(T, return_value_policy /* policy */, handle /* parent */) {
return none().inc_ref();
}
PYBIND11_TYPE_CASTER(void_type, _("None"));
PYBIND11_TYPE_CASTER(T, _("None"));
};
template <> class type_caster<void_type> : public void_caster<void_type> {};
template <> class type_caster<void> : public type_caster<void_type> {
public:
using type_caster<void_type>::cast;

View File

@ -205,7 +205,7 @@ template<typename T> struct optional_caster {
static handle cast(const T& src, return_value_policy policy, handle parent) {
if (!src)
return none();
return none().inc_ref();
return caster_type::cast(*src, policy, parent);
}
@ -232,11 +232,17 @@ private:
#if PYBIND11_HAS_OPTIONAL
template<typename T> struct type_caster<std::optional<T>>
: public optional_caster<std::optional<T>> {};
template<> struct type_caster<std::nullopt_t>
: public void_caster<std::nullopt_t> {};
#endif
#if PYBIND11_HAS_EXP_OPTIONAL
template<typename T> struct type_caster<std::experimental::optional<T>>
: public optional_caster<std::experimental::optional<T>> {};
template<> struct type_caster<std::experimental::nullopt_t>
: public void_caster<std::experimental::nullopt_t> {};
#endif
NAMESPACE_END(detail)

View File

@ -301,6 +301,9 @@ test_initializer python_types([](py::module &m) {
m.def("half_or_none", [](int x) -> opt_int {
return x ? opt_int(x / 2) : opt_int();
});
m.def("test_nullopt", [](opt_int x) {
return x.value_or(42);
}, py::arg_v("x", std::experimental::nullopt, "None"));
#endif
m.attr("has_optional") = py::cast(has_optional);
});

View File

@ -299,7 +299,7 @@ def test_accessors():
@pytest.mark.skipif(not has_optional, reason='no <experimental/optional>')
def test_optional():
from pybind11_tests import double_or_zero, half_or_none
from pybind11_tests import double_or_zero, half_or_none, test_nullopt
assert double_or_zero(None) == 0
assert double_or_zero(42) == 84
@ -308,3 +308,8 @@ def test_optional():
assert half_or_none(0) is None
assert half_or_none(42) == 21
pytest.raises(TypeError, half_or_none, 'foo')
assert test_nullopt() == 42
assert test_nullopt(None) == 42
assert test_nullopt(42) == 42
assert test_nullopt(43) == 43