9
9
10
10
#define NB_TYPE_CASTER (Value_, descr ) \
11
11
using Value = Value_; \
12
- static constexpr bool IsClass = false ; \
13
12
static constexpr auto Name = descr; \
14
13
template <typename T_> using Cast = movable_cast_t <T_>; \
15
14
static handle from_cpp (Value *p, rv_policy policy, cleanup_list *list) { \
16
15
if (!p) \
17
16
return none ().release (); \
18
17
return from_cpp (*p, policy, list); \
19
18
} \
20
- explicit operator Value *() { return &value; } \
21
- explicit operator Value &() { return value; } \
22
- explicit operator Value &&() && { return (Value &&) value; } \
19
+ explicit operator Value*() { return &value; } \
20
+ explicit operator Value&() { return (Value &) value; } \
21
+ explicit operator Value&&() { return (Value &&) value; } \
23
22
Value value;
24
23
25
24
#define NB_MAKE_OPAQUE (...) \
@@ -38,14 +37,45 @@ enum cast_flags : uint8_t {
38
37
construct = (1 << 1 )
39
38
};
40
39
40
+ /* *
41
+ * Type casters expose a member 'Cast<T>' which users of a type caster must
42
+ * query to determine what the caster actually can (and prefers) to produce.
43
+ * The convenience alias ``cast_t<T>`` defined below performs this query for a
44
+ * given type ``T``.
45
+ *
46
+ * Often ``cast_t<T>`` is simply equal to ``T`` or ``T&``. More significant
47
+ * deviations are also possible, which could be due to one of the following
48
+ * two reasons:
49
+ *
50
+ * 1. Efficiency: most STL type casters create a local copy (``value`` member)
51
+ * of the value being cast. The caller should move this value to its
52
+ * intended destination instead of making further copies along the way.
53
+ * Consequently, ``cast_t<std::vector<T>>`` yields ``cast_t<std::vector<T>>
54
+ * &&`` to enable such behavior.
55
+ *
56
+ * 2. STL pairs may contain references, and such pairs aren't
57
+ * default-constructible. The STL pair caster therefore cannot create a local
58
+ * copy and must construct the pair on the fly, which in turns means that it
59
+ * cannot return references. Therefore, ``cast_t<const std::pair<T1, T2>&>``
60
+ * yields ``std::pair<T1, T2>``.
61
+ */
62
+
63
+ // / Ask a type caster what flavors of a type it can actually produce -- may be different from 'T'
41
64
template <typename T> using cast_t = typename make_caster<T>::template Cast<T>;
42
65
66
+ // / This is a default choice for the 'Cast' type alias described above. It
67
+ // / prefers to return rvalue references to allow the caller to move the object.
43
68
template <typename T>
44
- using simple_cast_t =
45
- std::conditional_t <is_pointer_v<T>, intrinsic_t <T> *, intrinsic_t <T> &>;
69
+ using movable_cast_t =
70
+ std::conditional_t <is_pointer_v<T>, intrinsic_t <T> *,
71
+ std::conditional_t <std::is_lvalue_reference_v<T>,
72
+ intrinsic_t <T> &, intrinsic_t <T> &&>>;
46
73
74
+ // / This version is more careful about what the caller actually requested and
75
+ // / only moves when this was explicitly requested. It is the default for the
76
+ // / base type caster (i.e., types bound via ``nanobind::class_<..>``)
47
77
template <typename T>
48
- using movable_cast_t =
78
+ using precise_cast_t =
49
79
std::conditional_t <is_pointer_v<T>, intrinsic_t <T> *,
50
80
std::conditional_t <std::is_rvalue_reference_v<T>,
51
81
intrinsic_t <T> &&, intrinsic_t <T> &>>;
@@ -105,13 +135,11 @@ struct type_caster<T, enable_if_t<std::is_arithmetic_v<T> && !is_std_char_v<T>>>
105
135
106
136
template <> struct type_caster <void_type> {
107
137
static constexpr auto Name = const_name(" None" );
108
- static constexpr bool IsClass = false ;
109
138
};
110
139
111
140
template <> struct type_caster <void > {
112
141
template <typename T_> using Cast = void *;
113
142
using Value = void *;
114
- static constexpr bool IsClass = false ;
115
143
static constexpr auto Name = const_name(" capsule" );
116
144
explicit operator void *() { return value; }
117
145
Value value;
@@ -175,7 +203,6 @@ template <> struct type_caster<bool> {
175
203
template <> struct type_caster <char > {
176
204
using Value = const char *;
177
205
Value value;
178
- static constexpr bool IsClass = false ;
179
206
static constexpr auto Name = const_name(" str" );
180
207
template <typename T_>
181
208
using Cast = std::conditional_t <is_pointer_v<T_>, const char *, char >;
@@ -289,12 +316,10 @@ template <typename T> NB_INLINE rv_policy infer_policy(rv_policy policy) {
289
316
290
317
template <typename T, typename SFINAE = int > struct type_hook : std::false_type { };
291
318
292
- template <typename Type_> struct type_caster_base {
319
+ template <typename Type_> struct type_caster_base : type_caster_base_tag {
293
320
using Type = Type_;
294
321
static constexpr auto Name = const_name<Type>();
295
- static constexpr bool IsClass = true ;
296
-
297
- template <typename T> using Cast = movable_cast_t <T>;
322
+ template <typename T> using Cast = precise_cast_t <T>;
298
323
299
324
NB_INLINE bool from_python (handle src, uint8_t flags,
300
325
cleanup_list *cleanup) noexcept {
@@ -335,7 +360,7 @@ template <typename Type_> struct type_caster_base {
335
360
return *value;
336
361
}
337
362
338
- operator Type&&() && {
363
+ operator Type&&() {
339
364
raise_next_overload_if_null (value);
340
365
return (Type &&) *value;
341
366
}
@@ -352,7 +377,6 @@ NAMESPACE_END(detail)
352
377
template <typename T, typename Derived>
353
378
bool try_cast(const detail::api<Derived> &value, T &out, bool convert = true ) noexcept {
354
379
using Caster = detail::make_caster<T>;
355
- using Output = typename Caster::template Cast<T>;
356
380
357
381
static_assert (!std::is_same_v<const char *, T>,
358
382
" nanobind::try_cast(): cannot return a reference to a temporary." );
@@ -361,11 +385,7 @@ bool try_cast(const detail::api<Derived> &value, T &out, bool convert = true) no
361
385
if (caster.from_python (value.derived ().ptr (),
362
386
convert ? (uint8_t ) detail::cast_flags::convert
363
387
: (uint8_t ) 0 , nullptr )) {
364
- if constexpr (Caster::IsClass)
365
- out = caster.operator Output ();
366
- else
367
- out = std::move (caster.operator Output&&());
368
-
388
+ out = caster.operator detail::cast_t <T>();
369
389
return true ;
370
390
}
371
391
@@ -378,11 +398,11 @@ T cast(const detail::api<Derived> &value, bool convert = true) {
378
398
return ;
379
399
} else {
380
400
using Caster = detail::make_caster<T>;
381
- using Output = typename Caster::template Cast<T>;
382
401
383
402
static_assert (
384
- !(std::is_reference_v<T> || std::is_pointer_v<T>) || Caster::IsClass ||
385
- std::is_same_v<const char *, T>,
403
+ !(std::is_reference_v<T> || std::is_pointer_v<T>) ||
404
+ detail::is_base_caster_v<Caster> ||
405
+ std::is_same_v<const char *, T>,
386
406
" nanobind::cast(): cannot return a reference to a temporary." );
387
407
388
408
Caster caster;
@@ -397,7 +417,7 @@ T cast(const detail::api<Derived> &value, bool convert = true) {
397
417
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
398
418
#endif
399
419
400
- return caster.operator Output ();
420
+ return caster.operator detail:: cast_t <T> ();
401
421
402
422
#if defined(__GNUC__) && !defined(__clang__)
403
423
#pragma GCC diagnostic pop
@@ -411,6 +431,7 @@ object cast(T &&value, rv_policy policy = rv_policy::automatic_reference) {
411
431
policy, nullptr );
412
432
if (!h.is_valid ())
413
433
detail::raise_cast_error ();
434
+
414
435
return steal (h);
415
436
}
416
437
0 commit comments