mirror of
https://github.com/pybind/pybind11.git
synced 2026-03-14 20:27:47 +00:00
Introduce recursive_container_traits (#4623)
* Testing * Similar fix for std::vector * Fix infinite recursion check: 1) Apply to is_copy_assignable additionally 2) Check infinite recursion for map-like types * style: pre-commit fixes * Optional commit that demonstrates the limitations of this PR * Fix positioning of container bindings The bindings were previously in a block that was only activated if numpy was available. * Suggestions from code review: API side * Suggestions from code review: Test side * Suggestions from code review 1) Renaming: is_recursive_container and MutuallyRecursiveContainerPair(MV|VM) 2) Avoid ambiguous specializations of is_recursive_container * Some little fixes * Reordering of structs * Add recursive checks for is_move_constructible * Static testing for pybind11 type traits * More precise checking of recursive types Instead of a trait `is_recursive_container`, use a trait `recursive_container_traits` with dependent type `recursive_container_traits::type_to_check_recursively`. So, instead of just checking if a type is recursive and then trying to somehow deal with it, recursively-defined traits such as is_move_constructible can now directly ask this trait where the recursion should proceed. * Review suggestions 1. Use std::conditional 2. Fix typo * Remove leftover include from test --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -70,6 +70,44 @@ NestMap *times_hundred(int n) {
|
||||
return m;
|
||||
}
|
||||
|
||||
/*
|
||||
* Recursive data structures as test for issue #4623
|
||||
*/
|
||||
struct RecursiveVector : std::vector<RecursiveVector> {
|
||||
using Parent = std::vector<RecursiveVector>;
|
||||
using Parent::Parent;
|
||||
};
|
||||
|
||||
struct RecursiveMap : std::map<int, RecursiveMap> {
|
||||
using Parent = std::map<int, RecursiveMap>;
|
||||
using Parent::Parent;
|
||||
};
|
||||
|
||||
/*
|
||||
* Pybind11 does not catch more complicated recursion schemes, such as mutual
|
||||
* recursion.
|
||||
* In that case custom recursive_container_traits specializations need to be added,
|
||||
* thus manually telling pybind11 about the recursion.
|
||||
*/
|
||||
struct MutuallyRecursiveContainerPairMV;
|
||||
struct MutuallyRecursiveContainerPairVM;
|
||||
|
||||
struct MutuallyRecursiveContainerPairMV : std::map<int, MutuallyRecursiveContainerPairVM> {};
|
||||
struct MutuallyRecursiveContainerPairVM : std::vector<MutuallyRecursiveContainerPairMV> {};
|
||||
|
||||
namespace pybind11 {
|
||||
namespace detail {
|
||||
template <typename SFINAE>
|
||||
struct recursive_container_traits<MutuallyRecursiveContainerPairMV, SFINAE> {
|
||||
using type_to_check_recursively = recursive_bottom;
|
||||
};
|
||||
template <typename SFINAE>
|
||||
struct recursive_container_traits<MutuallyRecursiveContainerPairVM, SFINAE> {
|
||||
using type_to_check_recursively = recursive_bottom;
|
||||
};
|
||||
} // namespace detail
|
||||
} // namespace pybind11
|
||||
|
||||
TEST_SUBMODULE(stl_binders, m) {
|
||||
// test_vector_int
|
||||
py::bind_vector<std::vector<unsigned int>>(m, "VectorInt", py::buffer_protocol());
|
||||
@@ -129,6 +167,12 @@ TEST_SUBMODULE(stl_binders, m) {
|
||||
m, "VectorUndeclStruct", py::buffer_protocol());
|
||||
});
|
||||
|
||||
// Bind recursive container types
|
||||
py::bind_vector<RecursiveVector>(m, "RecursiveVector");
|
||||
py::bind_map<RecursiveMap>(m, "RecursiveMap");
|
||||
py::bind_map<MutuallyRecursiveContainerPairMV>(m, "MutuallyRecursiveContainerPairMV");
|
||||
py::bind_vector<MutuallyRecursiveContainerPairVM>(m, "MutuallyRecursiveContainerPairVM");
|
||||
|
||||
// The rest depends on numpy:
|
||||
try {
|
||||
py::module_::import("numpy");
|
||||
|
||||
Reference in New Issue
Block a user