Skip to content

Commit a67d786

Browse files
fix(stl_bind): Enable bind_map with using declarations. (#4952)
* Enable `bind_map` with `using` declarations. * style: pre-commit fixes * Enable directives in bind_vector * Add tests for bind_ and using directives * style: pre-commit fixes * Remove C++17 functions * Fix test comment * Add minimal user like map py test --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 4bb6163 commit a67d786

File tree

3 files changed

+87
-2
lines changed

3 files changed

+87
-2
lines changed

include/pybind11/stl_bind.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, A
525525
[](const Vector &v) -> bool { return !v.empty(); },
526526
"Check whether the list is nonempty");
527527

528-
cl.def("__len__", &Vector::size);
528+
cl.def("__len__", [](const Vector &vec) { return vec.size(); });
529529

530530
#if 0
531531
// C++ style functions deprecated, leaving it here as an example
@@ -843,7 +843,8 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
843843
m.erase(it);
844844
});
845845

846-
cl.def("__len__", &Map::size);
846+
// Always use a lambda in case of `using` declaration
847+
cl.def("__len__", [](const Map &m) { return m.size(); });
847848

848849
return cl;
849850
}

tests/test_stl_binders.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <deque>
1616
#include <map>
1717
#include <unordered_map>
18+
#include <vector>
1819

1920
class El {
2021
public:
@@ -83,6 +84,71 @@ struct RecursiveMap : std::map<int, RecursiveMap> {
8384
using Parent::Parent;
8485
};
8586

87+
class UserVectorLike : private std::vector<int> {
88+
public:
89+
// This is only a subset of the member functions, as needed at the time.
90+
using Base = std::vector<int>;
91+
using typename Base::const_iterator;
92+
using typename Base::difference_type;
93+
using typename Base::iterator;
94+
using typename Base::size_type;
95+
using typename Base::value_type;
96+
97+
using Base::at;
98+
using Base::back;
99+
using Base::Base;
100+
using Base::begin;
101+
using Base::cbegin;
102+
using Base::cend;
103+
using Base::clear;
104+
using Base::empty;
105+
using Base::end;
106+
using Base::erase;
107+
using Base::front;
108+
using Base::insert;
109+
using Base::pop_back;
110+
using Base::push_back;
111+
using Base::reserve;
112+
using Base::shrink_to_fit;
113+
using Base::swap;
114+
using Base::operator[];
115+
using Base::capacity;
116+
using Base::size;
117+
};
118+
119+
bool operator==(UserVectorLike const &, UserVectorLike const &) { return true; }
120+
bool operator!=(UserVectorLike const &, UserVectorLike const &) { return false; }
121+
122+
class UserMapLike : private std::map<int, int> {
123+
public:
124+
// This is only a subset of the member functions, as needed at the time.
125+
using Base = std::map<int, int>;
126+
using typename Base::const_iterator;
127+
using typename Base::iterator;
128+
using typename Base::key_type;
129+
using typename Base::mapped_type;
130+
using typename Base::size_type;
131+
using typename Base::value_type;
132+
133+
using Base::at;
134+
using Base::Base;
135+
using Base::begin;
136+
using Base::cbegin;
137+
using Base::cend;
138+
using Base::clear;
139+
using Base::emplace;
140+
using Base::emplace_hint;
141+
using Base::empty;
142+
using Base::end;
143+
using Base::erase;
144+
using Base::find;
145+
using Base::insert;
146+
using Base::max_size;
147+
using Base::swap;
148+
using Base::operator[];
149+
using Base::size;
150+
};
151+
86152
/*
87153
* Pybind11 does not catch more complicated recursion schemes, such as mutual
88154
* recursion.
@@ -173,6 +239,10 @@ TEST_SUBMODULE(stl_binders, m) {
173239
py::bind_map<MutuallyRecursiveContainerPairMV>(m, "MutuallyRecursiveContainerPairMV");
174240
py::bind_vector<MutuallyRecursiveContainerPairVM>(m, "MutuallyRecursiveContainerPairVM");
175241

242+
// Bind with private inheritance + `using` directives.
243+
py::bind_vector<UserVectorLike>(m, "UserVectorLike");
244+
py::bind_map<UserMapLike>(m, "UserMapLike");
245+
176246
// The rest depends on numpy:
177247
try {
178248
py::module_::import("numpy");

tests/test_stl_binders.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,3 +353,17 @@ def test_recursive_map():
353353
recursive_map[100][101] = m.RecursiveMap()
354354
recursive_map[100][102] = m.RecursiveMap()
355355
assert list(recursive_map[100].keys()) == [101, 102]
356+
357+
358+
def test_user_vector_like():
359+
vec = m.UserVectorLike()
360+
vec.append(2)
361+
assert vec[0] == 2
362+
assert len(vec) == 1
363+
364+
365+
def test_user_like_map():
366+
map = m.UserMapLike()
367+
map[33] = 44
368+
assert map[33] == 44
369+
assert len(map) == 1

0 commit comments

Comments
 (0)