Skip to content

Commit eba6239

Browse files
committed
Static testing for pybind11 type traits
1 parent a839f8f commit eba6239

File tree

2 files changed

+243
-1
lines changed

2 files changed

+243
-1
lines changed

include/pybind11/detail/type_caster_base.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -921,7 +921,11 @@ struct is_copy_assignable<
921921
: is_copy_assignable<typename Container::value_type> {};
922922
template <typename T1, typename T2>
923923
struct is_copy_assignable<std::pair<T1, T2>>
924-
: all_of<is_copy_assignable<T1>, is_copy_assignable<T2>> {};
924+
/*
925+
* Need to remove the const qualifier from T1 here since the value_type in
926+
* STL map types is std::pair<const Key, T>, and const types are never assignable
927+
*/
928+
: all_of<is_copy_assignable<typename std::remove_const<T1>::type>, is_copy_assignable<T2>> {};
925929

926930
PYBIND11_NAMESPACE_END(detail)
927931

tests/test_copy_move.cpp

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include "constructor_stats.h"
1414
#include "pybind11_tests.h"
1515

16+
#include <type_traits>
17+
1618
template <typename derived>
1719
struct empty {
1820
static const derived &get_one() { return instance_; }
@@ -293,3 +295,239 @@ TEST_SUBMODULE(copy_move_policies, m) {
293295
// Make sure that cast from pytype rvalue to other pytype works
294296
m.def("get_pytype_rvalue_castissue", [](double i) { return py::float_(i).cast<py::int_>(); });
295297
}
298+
299+
/*
300+
* Rest of the file:
301+
* static_assert based tests for pybind11 adaptations of of
302+
* std::is_move_constructible, std::is_copy_constructible and
303+
* std::is_copy_assignable (no adaptation of std::is_move_assignable).
304+
* Difference between pybind11 and std traits: pybind11 traits will also check
305+
* the contained value_types.
306+
*/
307+
308+
struct NotMovable {
309+
NotMovable() = default;
310+
NotMovable(NotMovable const &) = default;
311+
NotMovable(NotMovable &&) = delete;
312+
NotMovable &operator=(NotMovable const &) = default;
313+
NotMovable &operator=(NotMovable &&) = delete;
314+
};
315+
static_assert(!std::is_move_constructible<NotMovable>::value,
316+
"!std::is_move_constructible<NotMovable>::value");
317+
static_assert(std::is_copy_constructible<NotMovable>::value,
318+
"std::is_copy_constructible<NotMovable>::value");
319+
static_assert(!pybind11::detail::is_move_constructible<NotMovable>::value,
320+
"!pybind11::detail::is_move_constructible<NotMovable>::value");
321+
static_assert(pybind11::detail::is_copy_constructible<NotMovable>::value,
322+
"pybind11::detail::is_copy_constructible<NotMovable>::value");
323+
static_assert(!std::is_move_assignable<NotMovable>::value,
324+
"!std::is_move_assignable<NotMovable>::value");
325+
static_assert(std::is_copy_assignable<NotMovable>::value,
326+
"std::is_copy_assignable<NotMovable>::value");
327+
// pybind11 does not have this
328+
// static_assert(!pybind11::detail::is_move_assignable<NotMovable>::value,
329+
// "!pybind11::detail::is_move_assignable<NotMovable>::value");
330+
static_assert(pybind11::detail::is_copy_assignable<NotMovable>::value,
331+
"pybind11::detail::is_copy_assignable<NotMovable>::value");
332+
333+
struct NotCopyable {
334+
NotCopyable() = default;
335+
NotCopyable(NotCopyable const &) = delete;
336+
NotCopyable(NotCopyable &&) = default;
337+
NotCopyable &operator=(NotCopyable const &) = delete;
338+
NotCopyable &operator=(NotCopyable &&) = default;
339+
};
340+
static_assert(std::is_move_constructible<NotCopyable>::value,
341+
"std::is_move_constructible<NotCopyable>::value");
342+
static_assert(!std::is_copy_constructible<NotCopyable>::value,
343+
"!std::is_copy_constructible<NotCopyable>::value");
344+
static_assert(pybind11::detail::is_move_constructible<NotCopyable>::value,
345+
"pybind11::detail::is_move_constructible<NotCopyable>::value");
346+
static_assert(!pybind11::detail::is_copy_constructible<NotCopyable>::value,
347+
"!pybind11::detail::is_copy_constructible<NotCopyable>::value");
348+
static_assert(std::is_move_assignable<NotCopyable>::value,
349+
"std::is_move_assignable<NotCopyable>::value");
350+
static_assert(!std::is_copy_assignable<NotCopyable>::value,
351+
"!std::is_copy_assignable<NotCopyable>::value");
352+
// pybind11 does not have this
353+
// static_assert(!pybind11::detail::is_move_assignable<NotCopyable>::value,
354+
// "!pybind11::detail::is_move_assignable<NotCopyable>::value");
355+
static_assert(!pybind11::detail::is_copy_assignable<NotCopyable>::value,
356+
"!pybind11::detail::is_copy_assignable<NotCopyable>::value");
357+
358+
struct NotCopyableNotMovable {
359+
NotCopyableNotMovable() = default;
360+
NotCopyableNotMovable(NotCopyableNotMovable const &) = delete;
361+
NotCopyableNotMovable(NotCopyableNotMovable &&) = delete;
362+
NotCopyableNotMovable &operator=(NotCopyableNotMovable const &) = delete;
363+
NotCopyableNotMovable &operator=(NotCopyableNotMovable &&) = delete;
364+
};
365+
static_assert(!std::is_move_constructible<NotCopyableNotMovable>::value,
366+
"!std::is_move_constructible<NotCopyableNotMovable>::value");
367+
static_assert(!std::is_copy_constructible<NotCopyableNotMovable>::value,
368+
"!std::is_copy_constructible<NotCopyableNotMovable>::value");
369+
static_assert(!pybind11::detail::is_move_constructible<NotCopyableNotMovable>::value,
370+
"!pybind11::detail::is_move_constructible<NotCopyableNotMovable>::value");
371+
static_assert(!pybind11::detail::is_copy_constructible<NotCopyableNotMovable>::value,
372+
"!pybind11::detail::is_copy_constructible<NotCopyableNotMovable>::value");
373+
static_assert(!std::is_move_assignable<NotCopyableNotMovable>::value,
374+
"!std::is_move_assignable<NotCopyableNotMovable>::value");
375+
static_assert(!std::is_copy_assignable<NotCopyableNotMovable>::value,
376+
"!std::is_copy_assignable<NotCopyableNotMovable>::value");
377+
// pybind11 does not have this
378+
// static_assert(!pybind11::detail::is_move_assignable<NotCopyableNotMovable>::value,
379+
// "!pybind11::detail::is_move_assignable<NotCopyableNotMovable>::value");
380+
static_assert(!pybind11::detail::is_copy_assignable<NotCopyableNotMovable>::value,
381+
"!pybind11::detail::is_copy_assignable<NotCopyableNotMovable>::value");
382+
383+
struct NotMovableVector : std::vector<NotMovable> {};
384+
static_assert(std::is_move_constructible<NotMovableVector>::value,
385+
"std::is_move_constructible<NotMovableVector>::value");
386+
static_assert(std::is_copy_constructible<NotMovableVector>::value,
387+
"std::is_copy_constructible<NotMovableVector>::value");
388+
static_assert(!pybind11::detail::is_move_constructible<NotMovableVector>::value,
389+
"!pybind11::detail::is_move_constructible<NotMovableVector>::value");
390+
static_assert(pybind11::detail::is_copy_constructible<NotMovableVector>::value,
391+
"pybind11::detail::is_copy_constructible<NotMovableVector>::value");
392+
static_assert(std::is_move_assignable<NotMovableVector>::value,
393+
"std::is_move_assignable<NotMovableVector>::value");
394+
static_assert(std::is_copy_assignable<NotMovableVector>::value,
395+
"std::is_copy_assignable<NotMovableVector>::value");
396+
// pybind11 does not have this
397+
// static_assert(!pybind11::detail::is_move_assignable<NotMovableVector>::value,
398+
// "!pybind11::detail::is_move_assignable<NotMovableVector>::value");
399+
static_assert(pybind11::detail::is_copy_assignable<NotMovableVector>::value,
400+
"pybind11::detail::is_copy_assignable<NotMovableVector>::value");
401+
402+
struct NotCopyableVector : std::vector<NotCopyable> {};
403+
static_assert(std::is_move_constructible<NotCopyableVector>::value,
404+
"std::is_move_constructible<NotCopyableVector>::value");
405+
static_assert(std::is_copy_constructible<NotCopyableVector>::value,
406+
"std::is_copy_constructible<NotCopyableVector>::value");
407+
static_assert(pybind11::detail::is_move_constructible<NotCopyableVector>::value,
408+
"pybind11::detail::is_move_constructible<NotCopyableVector>::value");
409+
static_assert(!pybind11::detail::is_copy_constructible<NotCopyableVector>::value,
410+
"!pybind11::detail::is_copy_constructible<NotCopyableVector>::value");
411+
static_assert(std::is_move_assignable<NotCopyableVector>::value,
412+
"std::is_move_assignable<NotCopyableVector>::value");
413+
static_assert(std::is_copy_assignable<NotCopyableVector>::value,
414+
"std::is_copy_assignable<NotCopyableVector>::value");
415+
// pybind11 does not have this
416+
// static_assert(!pybind11::detail::is_move_assignable<NotCopyableVector>::value,
417+
// "!pybind11::detail::is_move_assignable<NotCopyableVector>::value");
418+
static_assert(!pybind11::detail::is_copy_assignable<NotCopyableVector>::value,
419+
"!pybind11::detail::is_copy_assignable<NotCopyableVector>::value");
420+
421+
struct NotCopyableNotMovableVector : std::vector<NotCopyableNotMovable> {};
422+
static_assert(std::is_move_constructible<NotCopyableNotMovableVector>::value,
423+
"std::is_move_constructible<NotCopyableNotMovableVector>::value");
424+
static_assert(std::is_copy_constructible<NotCopyableNotMovableVector>::value,
425+
"std::is_copy_constructible<NotCopyableNotMovableVector>::value");
426+
static_assert(!pybind11::detail::is_move_constructible<NotCopyableNotMovableVector>::value,
427+
"!pybind11::detail::is_move_constructible<NotCopyableNotMovableVector>::value");
428+
static_assert(!pybind11::detail::is_copy_constructible<NotCopyableNotMovableVector>::value,
429+
"!pybind11::detail::is_copy_constructible<NotCopyableNotMovableVector>::value");
430+
static_assert(std::is_move_assignable<NotCopyableNotMovableVector>::value,
431+
"std::is_move_assignable<NotCopyableNotMovableVector>::value");
432+
static_assert(std::is_copy_assignable<NotCopyableNotMovableVector>::value,
433+
"std::is_copy_assignable<NotCopyableNotMovableVector>::value");
434+
// pybind11 does not have this
435+
// static_assert(!pybind11::detail::is_move_assignable<NotCopyableNotMovableVector>::value,
436+
// "!pybind11::detail::is_move_assignable<NotCopyableNotMovableVector>::value");
437+
static_assert(!pybind11::detail::is_copy_assignable<NotCopyableNotMovableVector>::value,
438+
"!pybind11::detail::is_copy_assignable<NotCopyableNotMovableVector>::value");
439+
440+
struct NotMovableMap : std::map<int, NotMovable> {};
441+
static_assert(std::is_move_constructible<NotMovableMap>::value,
442+
"std::is_move_constructible<NotMovableMap>::value");
443+
static_assert(std::is_copy_constructible<NotMovableMap>::value,
444+
"std::is_copy_constructible<NotMovableMap>::value");
445+
static_assert(!pybind11::detail::is_move_constructible<NotMovableMap>::value,
446+
"!pybind11::detail::is_move_constructible<NotMovableMap>::value");
447+
static_assert(pybind11::detail::is_copy_constructible<NotMovableMap>::value,
448+
"pybind11::detail::is_copy_constructible<NotMovableMap>::value");
449+
static_assert(std::is_move_assignable<NotMovableMap>::value,
450+
"std::is_move_assignable<NotMovableMap>::value");
451+
static_assert(std::is_copy_assignable<NotMovableMap>::value,
452+
"std::is_copy_assignable<NotMovableMap>::value");
453+
// pybind11 does not have this
454+
// static_assert(!pybind11::detail::is_move_assignable<NotMovableMap>::value,
455+
// "!pybind11::detail::is_move_assignable<NotMovableMap>::value");
456+
static_assert(pybind11::detail::is_copy_assignable<NotMovableMap>::value,
457+
"pybind11::detail::is_copy_assignable<NotMovableMap>::value");
458+
459+
struct NotCopyableMap : std::map<int, NotCopyable> {};
460+
static_assert(std::is_move_constructible<NotCopyableMap>::value,
461+
"std::is_move_constructible<NotCopyableMap>::value");
462+
static_assert(std::is_copy_constructible<NotCopyableMap>::value,
463+
"std::is_copy_constructible<NotCopyableMap>::value");
464+
static_assert(pybind11::detail::is_move_constructible<NotCopyableMap>::value,
465+
"pybind11::detail::is_move_constructible<NotCopyableMap>::value");
466+
static_assert(!pybind11::detail::is_copy_constructible<NotCopyableMap>::value,
467+
"!pybind11::detail::is_copy_constructible<NotCopyableMap>::value");
468+
static_assert(std::is_move_assignable<NotCopyableMap>::value,
469+
"std::is_move_assignable<NotCopyableMap>::value");
470+
static_assert(std::is_copy_assignable<NotCopyableMap>::value,
471+
"std::is_copy_assignable<NotCopyableMap>::value");
472+
// pybind11 does not have this
473+
// static_assert(!pybind11::detail::is_move_assignable<NotCopyableMap>::value,
474+
// "!pybind11::detail::is_move_assignable<NotCopyableMap>::value");
475+
static_assert(!pybind11::detail::is_copy_assignable<NotCopyableMap>::value,
476+
"!pybind11::detail::is_copy_assignable<NotCopyableMap>::value");
477+
478+
struct NotCopyableNotMovableMap : std::map<int, NotCopyableNotMovable> {};
479+
static_assert(std::is_move_constructible<NotCopyableNotMovableMap>::value,
480+
"std::is_move_constructible<NotCopyableNotMovableMap>::value");
481+
static_assert(std::is_copy_constructible<NotCopyableNotMovableMap>::value,
482+
"std::is_copy_constructible<NotCopyableNotMovableMap>::value");
483+
static_assert(!pybind11::detail::is_move_constructible<NotCopyableNotMovableMap>::value,
484+
"!pybind11::detail::is_move_constructible<NotCopyableNotMovableMap>::value");
485+
static_assert(!pybind11::detail::is_copy_constructible<NotCopyableNotMovableMap>::value,
486+
"!pybind11::detail::is_copy_constructible<NotCopyableNotMovableMap>::value");
487+
static_assert(std::is_move_assignable<NotCopyableNotMovableMap>::value,
488+
"std::is_move_assignable<NotCopyableNotMovableMap>::value");
489+
static_assert(std::is_copy_assignable<NotCopyableNotMovableMap>::value,
490+
"std::is_copy_assignable<NotCopyableNotMovableMap>::value");
491+
// pybind11 does not have this
492+
// static_assert(!pybind11::detail::is_move_assignable<NotCopyableNotMovableMap>::value,
493+
// "!pybind11::detail::is_move_assignable<NotCopyableNotMovableMap>::value");
494+
static_assert(!pybind11::detail::is_copy_assignable<NotCopyableNotMovableMap>::value,
495+
"!pybind11::detail::is_copy_assignable<NotCopyableNotMovableMap>::value");
496+
497+
struct RecursiveVector : std::vector<RecursiveVector> {};
498+
static_assert(std::is_move_constructible<RecursiveVector>::value,
499+
"std::is_move_constructible<RecursiveVector>::value");
500+
static_assert(std::is_copy_constructible<RecursiveVector>::value,
501+
"std::is_copy_constructible<RecursiveVector>::value");
502+
static_assert(pybind11::detail::is_move_constructible<RecursiveVector>::value,
503+
"pybind11::detail::is_move_constructible<RecursiveVector>::value");
504+
static_assert(pybind11::detail::is_copy_constructible<RecursiveVector>::value,
505+
"pybind11::detail::is_copy_constructible<RecursiveVector>::value");
506+
static_assert(std::is_move_assignable<RecursiveVector>::value,
507+
"std::is_move_assignable<RecursiveVector>::value");
508+
static_assert(std::is_copy_assignable<RecursiveVector>::value,
509+
"std::is_copy_assignable<RecursiveVector>::value");
510+
// pybind11 does not have this
511+
// static_assert(!pybind11::detail::is_move_assignable<RecursiveVector>::value,
512+
// "!pybind11::detail::is_move_assignable<RecursiveVector>::value");
513+
static_assert(pybind11::detail::is_copy_assignable<RecursiveVector>::value,
514+
"pybind11::detail::is_copy_assignable<RecursiveVector>::value");
515+
516+
struct RecursiveMap : std::map<int, RecursiveMap> {};
517+
static_assert(std::is_move_constructible<RecursiveMap>::value,
518+
"std::is_move_constructible<RecursiveMap>::value");
519+
static_assert(std::is_copy_constructible<RecursiveMap>::value,
520+
"std::is_copy_constructible<RecursiveMap>::value");
521+
static_assert(pybind11::detail::is_move_constructible<RecursiveMap>::value,
522+
"pybind11::detail::is_move_constructible<RecursiveMap>::value");
523+
static_assert(pybind11::detail::is_copy_constructible<RecursiveMap>::value,
524+
"pybind11::detail::is_copy_constructible<RecursiveMap>::value");
525+
static_assert(std::is_move_assignable<RecursiveMap>::value,
526+
"std::is_move_assignable<RecursiveMap>::value");
527+
static_assert(std::is_copy_assignable<RecursiveMap>::value,
528+
"std::is_copy_assignable<RecursiveMap>::value");
529+
// pybind11 does not have this
530+
// static_assert(!pybind11::detail::is_move_assignable<RecursiveMap>::value,
531+
// "!pybind11::detail::is_move_assignable<RecursiveMap>::value");
532+
static_assert(pybind11::detail::is_copy_assignable<RecursiveMap>::value,
533+
"pybind11::detail::is_copy_assignable<RecursiveMap>::value");

0 commit comments

Comments
 (0)