Skip to content

Commit 07725c2

Browse files
authored
Introduce pybind11::detail::is_move_constructible (#4631)
To support the use case captured in the new test_vector_unique_ptr_member.cpp
1 parent 071f35a commit 07725c2

File tree

6 files changed

+79
-5
lines changed

6 files changed

+79
-5
lines changed

include/pybind11/cast.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -964,7 +964,7 @@ struct move_always<
964964
enable_if_t<
965965
all_of<move_is_plain_type<T>,
966966
negation<is_copy_constructible<T>>,
967-
std::is_move_constructible<T>,
967+
is_move_constructible<T>,
968968
std::is_same<decltype(std::declval<make_caster<T>>().operator T &()), T &>>::value>>
969969
: std::true_type {};
970970
template <typename T, typename SFINAE = void>
@@ -975,7 +975,7 @@ struct move_if_unreferenced<
975975
enable_if_t<
976976
all_of<move_is_plain_type<T>,
977977
negation<move_always<T>>,
978-
std::is_move_constructible<T>,
978+
is_move_constructible<T>,
979979
std::is_same<decltype(std::declval<make_caster<T>>().operator T &()), T &>>::value>>
980980
: std::true_type {};
981981
template <typename T>

include/pybind11/detail/init.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
175175
template <typename Class>
176176
void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
177177
PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
178-
static_assert(std::is_move_constructible<Cpp<Class>>::value,
178+
static_assert(is_move_constructible<Cpp<Class>>::value,
179179
"pybind11::init() return-by-value factory function requires a movable class");
180180
if (Class::has_alias && need_alias) {
181181
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) {
190190
template <typename Class>
191191
void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
192192
static_assert(
193-
std::is_move_constructible<Alias<Class>>::value,
193+
is_move_constructible<Alias<Class>>::value,
194194
"pybind11::init() return-by-alias-value factory function requires a movable alias class");
195195
v_h.value_ptr() = new Alias<Class>(std::move(result));
196196
}

include/pybind11/detail/type_caster_base.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,9 @@ using movable_cast_op_type
827827
template <typename T, typename SFINAE = void>
828828
struct is_copy_constructible : std::is_copy_constructible<T> {};
829829

830+
template <typename T, typename SFINAE = void>
831+
struct is_move_constructible : std::is_move_constructible<T> {};
832+
830833
// Specialization for types that appear to be copy constructible but also look like stl containers
831834
// (we specifically check for: has `value_type` and `reference` with `reference = value_type&`): if
832835
// so, copy constructability depends on whether the value_type is copy constructible.
@@ -994,7 +997,7 @@ class type_caster_base : public type_caster_generic {
994997
return [](const void *arg) -> void * { return new T(*reinterpret_cast<const T *>(arg)); };
995998
}
996999

997-
template <typename T, typename = enable_if_t<std::is_move_constructible<T>::value>>
1000+
template <typename T, typename = enable_if_t<is_move_constructible<T>::value>>
9981001
static auto make_move_constructor(const T *)
9991002
-> decltype(new T(std::declval<T &&>()), Constructor{}) {
10001003
return [](const void *arg) -> void * {

tests/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ set(PYBIND11_TEST_FILES
155155
test_tagbased_polymorphic
156156
test_thread
157157
test_union
158+
test_vector_unique_ptr_member
158159
test_virtual_functions)
159160

160161
# Invoking cmake with something like:
+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#include "pybind11_tests.h"
2+
3+
#include <cstddef>
4+
#include <memory>
5+
#include <vector>
6+
7+
namespace pybind11_tests {
8+
namespace vector_unique_ptr_member {
9+
10+
struct DataType {};
11+
12+
// Reduced from a use case in the wild.
13+
struct VectorOwner {
14+
static std::unique_ptr<VectorOwner> Create(std::size_t num_elems) {
15+
return std::unique_ptr<VectorOwner>(
16+
new VectorOwner(std::vector<std::unique_ptr<DataType>>(num_elems)));
17+
}
18+
19+
std::size_t data_size() const { return data_.size(); }
20+
21+
private:
22+
explicit VectorOwner(std::vector<std::unique_ptr<DataType>> data) : data_(std::move(data)) {}
23+
24+
const std::vector<std::unique_ptr<DataType>> data_;
25+
};
26+
27+
} // namespace vector_unique_ptr_member
28+
} // namespace pybind11_tests
29+
30+
namespace pybind11 {
31+
namespace detail {
32+
33+
template <>
34+
struct is_copy_constructible<pybind11_tests::vector_unique_ptr_member::VectorOwner>
35+
: std::false_type {};
36+
37+
template <>
38+
struct is_move_constructible<pybind11_tests::vector_unique_ptr_member::VectorOwner>
39+
: std::false_type {};
40+
41+
} // namespace detail
42+
} // namespace pybind11
43+
44+
using namespace pybind11_tests::vector_unique_ptr_member;
45+
46+
py::object py_cast_VectorOwner_ptr(VectorOwner *ptr) { return py::cast(ptr); }
47+
48+
// PYBIND11_SMART_HOLDER_TYPE_CASTERS(VectorOwner)
49+
50+
TEST_SUBMODULE(vector_unique_ptr_member, m) {
51+
py::class_<VectorOwner>(m, "VectorOwner")
52+
.def_static("Create", &VectorOwner::Create)
53+
.def("data_size", &VectorOwner::data_size);
54+
55+
m.def("py_cast_VectorOwner_ptr", py_cast_VectorOwner_ptr);
56+
}
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import pytest
2+
3+
from pybind11_tests import vector_unique_ptr_member as m
4+
5+
6+
@pytest.mark.parametrize("num_elems", range(3))
7+
def test_create(num_elems):
8+
vo = m.VectorOwner.Create(num_elems)
9+
assert vo.data_size() == num_elems
10+
11+
12+
def test_cast():
13+
vo = m.VectorOwner.Create(0)
14+
assert m.py_cast_VectorOwner_ptr(vo) is vo

0 commit comments

Comments
 (0)