Skip to content

Commit 8fd16e2

Browse files
committed
Simplify alias-from-base construction logic
1 parent 2dfa0b0 commit 8fd16e2

File tree

1 file changed

+20
-22
lines changed

1 file changed

+20
-22
lines changed

include/pybind11/detail/init.h

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ template <typename Class> using Cpp = typename Class::type;
4545
template <typename Class> using Alias = typename Class::type_alias;
4646
template <typename Class> using Holder = typename Class::holder_type;
4747

48+
template <typename Class> using is_alias_constructible = std::is_constructible<Alias<Class>, Cpp<Class> &&>;
49+
4850
// Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance.
4951
template <typename Class, enable_if_t<Class::has_alias, int> = 0>
5052
bool is_alias(Cpp<Class> *ptr) {
@@ -59,15 +61,17 @@ constexpr bool is_alias(void *) { return false; }
5961
// constructed from an rvalue reference of the base Cpp type. This means that Alias classes
6062
// can, when appropriate, simply define a `Alias(Cpp &&)` constructor rather than needing to
6163
// inherit all the base class constructors.
62-
template <typename Class, enable_if_t<std::is_constructible<Alias<Class>, Cpp<Class> &&>::value, int> = 0>
63-
bool construct_alias_from_cpp(value_and_holder &v_h, Cpp<Class> &&base) {
64+
template <typename Class>
65+
void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/,
66+
value_and_holder &v_h, Cpp<Class> &&base) {
6467
deallocate(v_h) = new Alias<Class>(std::move(base));
65-
return true;
6668
}
67-
// Fallback of the above for aliases without an `Alias(Cpp &&) constructor; does nothing and
68-
// returns false to signal the non-availability of the special constructor.
69-
template <typename Class, enable_if_t<!std::is_constructible<Alias<Class>, Cpp<Class> &&>::value, int> = 0>
70-
constexpr bool construct_alias_from_cpp(value_and_holder &, Cpp<Class> &&) { return false; }
69+
template <typename Class>
70+
[[noreturn]] void construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/,
71+
value_and_holder &, Cpp<Class> &&) {
72+
throw type_error("pybind11::init(): unable to convert returned instance to required "
73+
"alias class: no `Alias<Class>(Class &&)` constructor available");
74+
}
7175

7276
// Error-generating fallback for factories that don't match one of the below construction
7377
// mechanisms.
@@ -101,15 +105,13 @@ void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
101105
v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null
102106
v_h.set_instance_registered(false);
103107

104-
if (construct_alias_from_cpp<Class>(v_h, std::move(*ptr)))
105-
return;
106-
else
107-
throw type_error("pybind11::init(): pointer could not be cast or "
108-
"converted to an alias instance");
108+
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
109+
}
110+
else {
111+
// Otherwise the type isn't inherited, so we don't need an Alias and can just store the Cpp
112+
// pointer directory:
113+
deallocate(v_h) = ptr;
109114
}
110-
// Otherwise the type isn't inherited, so we don't need an Alias and can just store the Cpp
111-
// pointer directory:
112-
deallocate(v_h) = ptr;
113115
}
114116

115117
// Pointer return v2: a factory that always returns an alias instance ptr. We simply take over
@@ -143,14 +145,10 @@ template <typename Class>
143145
void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
144146
static_assert(std::is_move_constructible<Cpp<Class>>::value,
145147
"pybind11::init() return-by-value factory function requires a movable class");
146-
if (Class::has_alias && need_alias) {
147-
if (!construct_alias_from_cpp<Class>(v_h, std::move(result)))
148-
throw type_error("pybind11::init(): unable to convert returned instance to "
149-
"required alias class: no `Alias<Class>(Class &&)` constructor available");
150-
}
151-
else {
148+
if (Class::has_alias && need_alias)
149+
construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
150+
else
152151
deallocate(v_h) = new Cpp<Class>(std::move(result));
153-
}
154152
}
155153

156154
// return-by-value version 2: returning a value of the alias type itself. We move-construct an

0 commit comments

Comments
 (0)