mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 05:05:11 +00:00
Introduce pybind11::detail::is_move_constructible
(#4631)
To support the use case captured in the new test_vector_unique_ptr_member.cpp
This commit is contained in:
parent
071f35ab85
commit
07725c28c0
@ -964,7 +964,7 @@ struct move_always<
|
|||||||
enable_if_t<
|
enable_if_t<
|
||||||
all_of<move_is_plain_type<T>,
|
all_of<move_is_plain_type<T>,
|
||||||
negation<is_copy_constructible<T>>,
|
negation<is_copy_constructible<T>>,
|
||||||
std::is_move_constructible<T>,
|
is_move_constructible<T>,
|
||||||
std::is_same<decltype(std::declval<make_caster<T>>().operator T &()), T &>>::value>>
|
std::is_same<decltype(std::declval<make_caster<T>>().operator T &()), T &>>::value>>
|
||||||
: std::true_type {};
|
: std::true_type {};
|
||||||
template <typename T, typename SFINAE = void>
|
template <typename T, typename SFINAE = void>
|
||||||
@ -975,7 +975,7 @@ struct move_if_unreferenced<
|
|||||||
enable_if_t<
|
enable_if_t<
|
||||||
all_of<move_is_plain_type<T>,
|
all_of<move_is_plain_type<T>,
|
||||||
negation<move_always<T>>,
|
negation<move_always<T>>,
|
||||||
std::is_move_constructible<T>,
|
is_move_constructible<T>,
|
||||||
std::is_same<decltype(std::declval<make_caster<T>>().operator T &()), T &>>::value>>
|
std::is_same<decltype(std::declval<make_caster<T>>().operator T &()), T &>>::value>>
|
||||||
: std::true_type {};
|
: std::true_type {};
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -175,7 +175,7 @@ void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
|
|||||||
template <typename Class>
|
template <typename Class>
|
||||||
void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
|
void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
|
||||||
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
|
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
|
||||||
static_assert(std::is_move_constructible<Cpp<Class>>::value,
|
static_assert(is_move_constructible<Cpp<Class>>::value,
|
||||||
"pybind11::init() return-by-value factory function requires a movable class");
|
"pybind11::init() return-by-value factory function requires a movable class");
|
||||||
if (Class::has_alias && need_alias) {
|
if (Class::has_alias && need_alias) {
|
||||||
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
|
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
|
||||||
@ -190,7 +190,7 @@ void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
|
|||||||
template <typename Class>
|
template <typename Class>
|
||||||
void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
|
void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
|
||||||
static_assert(
|
static_assert(
|
||||||
std::is_move_constructible<Alias<Class>>::value,
|
is_move_constructible<Alias<Class>>::value,
|
||||||
"pybind11::init() return-by-alias-value factory function requires a movable alias class");
|
"pybind11::init() return-by-alias-value factory function requires a movable alias class");
|
||||||
v_h.value_ptr() = new Alias<Class>(std::move(result));
|
v_h.value_ptr() = new Alias<Class>(std::move(result));
|
||||||
}
|
}
|
||||||
|
@ -827,6 +827,9 @@ using movable_cast_op_type
|
|||||||
template <typename T, typename SFINAE = void>
|
template <typename T, typename SFINAE = void>
|
||||||
struct is_copy_constructible : std::is_copy_constructible<T> {};
|
struct is_copy_constructible : std::is_copy_constructible<T> {};
|
||||||
|
|
||||||
|
template <typename T, typename SFINAE = void>
|
||||||
|
struct is_move_constructible : std::is_move_constructible<T> {};
|
||||||
|
|
||||||
// Specialization for types that appear to be copy constructible but also look like stl containers
|
// Specialization for types that appear to be copy constructible but also look like stl containers
|
||||||
// (we specifically check for: has `value_type` and `reference` with `reference = value_type&`): if
|
// (we specifically check for: has `value_type` and `reference` with `reference = value_type&`): if
|
||||||
// so, copy constructability depends on whether the value_type is copy constructible.
|
// so, copy constructability depends on whether the value_type is copy constructible.
|
||||||
@ -994,7 +997,7 @@ protected:
|
|||||||
return [](const void *arg) -> void * { return new T(*reinterpret_cast<const T *>(arg)); };
|
return [](const void *arg) -> void * { return new T(*reinterpret_cast<const T *>(arg)); };
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename = enable_if_t<std::is_move_constructible<T>::value>>
|
template <typename T, typename = enable_if_t<is_move_constructible<T>::value>>
|
||||||
static auto make_move_constructor(const T *)
|
static auto make_move_constructor(const T *)
|
||||||
-> decltype(new T(std::declval<T &&>()), Constructor{}) {
|
-> decltype(new T(std::declval<T &&>()), Constructor{}) {
|
||||||
return [](const void *arg) -> void * {
|
return [](const void *arg) -> void * {
|
||||||
|
@ -155,6 +155,7 @@ set(PYBIND11_TEST_FILES
|
|||||||
test_tagbased_polymorphic
|
test_tagbased_polymorphic
|
||||||
test_thread
|
test_thread
|
||||||
test_union
|
test_union
|
||||||
|
test_vector_unique_ptr_member
|
||||||
test_virtual_functions)
|
test_virtual_functions)
|
||||||
|
|
||||||
# Invoking cmake with something like:
|
# Invoking cmake with something like:
|
||||||
|
56
tests/test_vector_unique_ptr_member.cpp
Normal file
56
tests/test_vector_unique_ptr_member.cpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include "pybind11_tests.h"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace pybind11_tests {
|
||||||
|
namespace vector_unique_ptr_member {
|
||||||
|
|
||||||
|
struct DataType {};
|
||||||
|
|
||||||
|
// Reduced from a use case in the wild.
|
||||||
|
struct VectorOwner {
|
||||||
|
static std::unique_ptr<VectorOwner> Create(std::size_t num_elems) {
|
||||||
|
return std::unique_ptr<VectorOwner>(
|
||||||
|
new VectorOwner(std::vector<std::unique_ptr<DataType>>(num_elems)));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t data_size() const { return data_.size(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit VectorOwner(std::vector<std::unique_ptr<DataType>> data) : data_(std::move(data)) {}
|
||||||
|
|
||||||
|
const std::vector<std::unique_ptr<DataType>> data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace vector_unique_ptr_member
|
||||||
|
} // namespace pybind11_tests
|
||||||
|
|
||||||
|
namespace pybind11 {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct is_copy_constructible<pybind11_tests::vector_unique_ptr_member::VectorOwner>
|
||||||
|
: std::false_type {};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct is_move_constructible<pybind11_tests::vector_unique_ptr_member::VectorOwner>
|
||||||
|
: std::false_type {};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace pybind11
|
||||||
|
|
||||||
|
using namespace pybind11_tests::vector_unique_ptr_member;
|
||||||
|
|
||||||
|
py::object py_cast_VectorOwner_ptr(VectorOwner *ptr) { return py::cast(ptr); }
|
||||||
|
|
||||||
|
// PYBIND11_SMART_HOLDER_TYPE_CASTERS(VectorOwner)
|
||||||
|
|
||||||
|
TEST_SUBMODULE(vector_unique_ptr_member, m) {
|
||||||
|
py::class_<VectorOwner>(m, "VectorOwner")
|
||||||
|
.def_static("Create", &VectorOwner::Create)
|
||||||
|
.def("data_size", &VectorOwner::data_size);
|
||||||
|
|
||||||
|
m.def("py_cast_VectorOwner_ptr", py_cast_VectorOwner_ptr);
|
||||||
|
}
|
14
tests/test_vector_unique_ptr_member.py
Normal file
14
tests/test_vector_unique_ptr_member.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from pybind11_tests import vector_unique_ptr_member as m
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("num_elems", range(3))
|
||||||
|
def test_create(num_elems):
|
||||||
|
vo = m.VectorOwner.Create(num_elems)
|
||||||
|
assert vo.data_size() == num_elems
|
||||||
|
|
||||||
|
|
||||||
|
def test_cast():
|
||||||
|
vo = m.VectorOwner.Create(0)
|
||||||
|
assert m.py_cast_VectorOwner_ptr(vo) is vo
|
Loading…
Reference in New Issue
Block a user