Scarab  v2.9.1
Project 8 C++ Utility Library
stl_bind.h
Go to the documentation of this file.
1 /*
2  pybind11/std_bind.h: Binding generators for STL data types
3 
4  Copyright (c) 2016 Sergey Lyskov and Wenzel Jakob
5 
6  All rights reserved. Use of this source code is governed by a
7  BSD-style license that can be found in the LICENSE file.
8 */
9 
10 #pragma once
11 
12 #include "detail/common.h"
13 #include "operators.h"
14 
15 #include <algorithm>
16 #include <sstream>
17 
19 NAMESPACE_BEGIN(detail)
20 
21 /* SFINAE helper class used by 'is_comparable */
22 template <typename T> struct container_traits {
23  template <typename T2> static std::true_type test_comparable(decltype(std::declval<const T2 &>() == std::declval<const T2 &>())*);
24  template <typename T2> static std::false_type test_comparable(...);
25  template <typename T2> static std::true_type test_value(typename T2::value_type *);
26  template <typename T2> static std::false_type test_value(...);
27  template <typename T2> static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *);
28  template <typename T2> static std::false_type test_pair(...);
29 
30  static constexpr const bool is_comparable = std::is_same<std::true_type, decltype(test_comparable<T>(nullptr))>::value;
31  static constexpr const bool is_pair = std::is_same<std::true_type, decltype(test_pair<T>(nullptr, nullptr))>::value;
32  static constexpr const bool is_vector = std::is_same<std::true_type, decltype(test_value<T>(nullptr))>::value;
33  static constexpr const bool is_element = !is_pair && !is_vector;
34 };
35 
36 /* Default: is_comparable -> std::false_type */
37 template <typename T, typename SFINAE = void>
38 struct is_comparable : std::false_type { };
39 
40 /* For non-map data structures, check whether operator== can be instantiated */
41 template <typename T>
43  T, enable_if_t<container_traits<T>::is_element &&
45  : std::true_type { };
46 
47 /* For a vector/map data structure, recursively check the value type (which is std::pair for maps) */
48 template <typename T>
49 struct is_comparable<T, enable_if_t<container_traits<T>::is_vector>> {
50  static constexpr const bool value =
52 };
53 
54 /* For pairs, recursively check the two data types */
55 template <typename T>
56 struct is_comparable<T, enable_if_t<container_traits<T>::is_pair>> {
57  static constexpr const bool value =
60 };
61 
62 /* Fallback functions */
63 template <typename, typename, typename... Args> void vector_if_copy_constructible(const Args &...) { }
64 template <typename, typename, typename... Args> void vector_if_equal_operator(const Args &...) { }
65 template <typename, typename, typename... Args> void vector_if_insertion_operator(const Args &...) { }
66 template <typename, typename, typename... Args> void vector_modifiers(const Args &...) { }
67 
68 template<typename Vector, typename Class_>
70  cl.def(init<const Vector &>(), "Copy constructor");
71 }
72 
73 template<typename Vector, typename Class_>
75  using T = typename Vector::value_type;
76 
77  cl.def(self == self);
78  cl.def(self != self);
79 
80  cl.def("count",
81  [](const Vector &v, const T &x) {
82  return std::count(v.begin(), v.end(), x);
83  },
84  arg("x"),
85  "Return the number of times ``x`` appears in the list"
86  );
87 
88  cl.def("remove", [](Vector &v, const T &x) {
89  auto p = std::find(v.begin(), v.end(), x);
90  if (p != v.end())
91  v.erase(p);
92  else
93  throw value_error();
94  },
95  arg("x"),
96  "Remove the first item from the list whose value is x. "
97  "It is an error if there is no such item."
98  );
99 
100  cl.def("__contains__",
101  [](const Vector &v, const T &x) {
102  return std::find(v.begin(), v.end(), x) != v.end();
103  },
104  arg("x"),
105  "Return true the container contains ``x``"
106  );
107 }
108 
109 // Vector modifiers -- requires a copyable vector_type:
110 // (Technically, some of these (pop and __delitem__) don't actually require copyability, but it seems
111 // silly to allow deletion but not insertion, so include them here too.)
112 template <typename Vector, typename Class_>
114  using T = typename Vector::value_type;
115  using SizeType = typename Vector::size_type;
116  using DiffType = typename Vector::difference_type;
117 
118  auto wrap_i = [](DiffType i, SizeType n) {
119  if (i < 0)
120  i += n;
121  if (i < 0 || (SizeType)i >= n)
122  throw index_error();
123  return i;
124  };
125 
126  cl.def("append",
127  [](Vector &v, const T &value) { v.push_back(value); },
128  arg("x"),
129  "Add an item to the end of the list");
130 
131  cl.def(init([](iterable it) {
132  auto v = std::unique_ptr<Vector>(new Vector());
133  v->reserve(len_hint(it));
134  for (handle h : it)
135  v->push_back(h.cast<T>());
136  return v.release();
137  }));
138 
139  cl.def("extend",
140  [](Vector &v, const Vector &src) {
141  v.insert(v.end(), src.begin(), src.end());
142  },
143  arg("L"),
144  "Extend the list by appending all the items in the given list"
145  );
146 
147  cl.def("extend",
148  [](Vector &v, iterable it) {
149  const size_t old_size = v.size();
150  v.reserve(old_size + len_hint(it));
151  try {
152  for (handle h : it) {
153  v.push_back(h.cast<T>());
154  }
155  } catch (const cast_error &) {
156  v.erase(v.begin() + static_cast<typename Vector::difference_type>(old_size), v.end());
157  try {
158  v.shrink_to_fit();
159  } catch (const std::exception &) {
160  // Do nothing
161  }
162  throw;
163  }
164  },
165  arg("L"),
166  "Extend the list by appending all the items in the given list"
167  );
168 
169  cl.def("insert",
170  [](Vector &v, DiffType i, const T &x) {
171  // Can't use wrap_i; i == v.size() is OK
172  if (i < 0)
173  i += v.size();
174  if (i < 0 || (SizeType)i > v.size())
175  throw index_error();
176  v.insert(v.begin() + i, x);
177  },
178  arg("i") , arg("x"),
179  "Insert an item at a given position."
180  );
181 
182  cl.def("pop",
183  [](Vector &v) {
184  if (v.empty())
185  throw index_error();
186  T t = v.back();
187  v.pop_back();
188  return t;
189  },
190  "Remove and return the last item"
191  );
192 
193  cl.def("pop",
194  [wrap_i](Vector &v, DiffType i) {
195  i = wrap_i(i, v.size());
196  T t = v[(SizeType) i];
197  v.erase(v.begin() + i);
198  return t;
199  },
200  arg("i"),
201  "Remove and return the item at index ``i``"
202  );
203 
204  cl.def("__setitem__",
205  [wrap_i](Vector &v, DiffType i, const T &t) {
206  i = wrap_i(i, v.size());
207  v[(SizeType)i] = t;
208  }
209  );
210 
212  cl.def("__getitem__",
213  [](const Vector &v, slice slice) -> Vector * {
214  size_t start, stop, step, slicelength;
215 
216  if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
217  throw error_already_set();
218 
219  Vector *seq = new Vector();
220  seq->reserve((size_t) slicelength);
221 
222  for (size_t i=0; i<slicelength; ++i) {
223  seq->push_back(v[start]);
224  start += step;
225  }
226  return seq;
227  },
228  arg("s"),
229  "Retrieve list elements using a slice object"
230  );
231 
232  cl.def("__setitem__",
233  [](Vector &v, slice slice, const Vector &value) {
234  size_t start, stop, step, slicelength;
235  if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
236  throw error_already_set();
237 
238  if (slicelength != value.size())
239  throw std::runtime_error("Left and right hand size of slice assignment have different sizes!");
240 
241  for (size_t i=0; i<slicelength; ++i) {
242  v[start] = value[i];
243  start += step;
244  }
245  },
246  "Assign list elements using a slice object"
247  );
248 
249  cl.def("__delitem__",
250  [wrap_i](Vector &v, DiffType i) {
251  i = wrap_i(i, v.size());
252  v.erase(v.begin() + i);
253  },
254  "Delete the list elements at index ``i``"
255  );
256 
257  cl.def("__delitem__",
258  [](Vector &v, slice slice) {
259  size_t start, stop, step, slicelength;
260 
261  if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
262  throw error_already_set();
263 
264  if (step == 1 && false) {
265  v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength));
266  } else {
267  for (size_t i = 0; i < slicelength; ++i) {
268  v.erase(v.begin() + DiffType(start));
269  start += step - 1;
270  }
271  }
272  },
273  "Delete list elements using a slice object"
274  );
275 
276 }
277 
278 // If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>),
279 // we have to access by copying; otherwise we return by reference.
280 template <typename Vector> using vector_needs_copy = negation<
281  std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>>;
282 
283 // The usual case: access and iterate by reference
284 template <typename Vector, typename Class_>
286  using T = typename Vector::value_type;
287  using SizeType = typename Vector::size_type;
288  using DiffType = typename Vector::difference_type;
289  using ItType = typename Vector::iterator;
290 
291  auto wrap_i = [](DiffType i, SizeType n) {
292  if (i < 0)
293  i += n;
294  if (i < 0 || (SizeType)i >= n)
295  throw index_error();
296  return i;
297  };
298 
299  cl.def("__getitem__",
300  [wrap_i](Vector &v, DiffType i) -> T & {
301  i = wrap_i(i, v.size());
302  return v[(SizeType)i];
303  },
304  return_value_policy::reference_internal // ref + keepalive
305  );
306 
307  cl.def("__iter__",
308  [](Vector &v) {
309  return make_iterator<
310  return_value_policy::reference_internal, ItType, ItType, T&>(
311  v.begin(), v.end());
312  },
313  keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
314  );
315 }
316 
317 // The case for special objects, like std::vector<bool>, that have to be returned-by-copy:
318 template <typename Vector, typename Class_>
320  using T = typename Vector::value_type;
321  using SizeType = typename Vector::size_type;
322  using DiffType = typename Vector::difference_type;
323  using ItType = typename Vector::iterator;
324  cl.def("__getitem__",
325  [](const Vector &v, DiffType i) -> T {
326  if (i < 0 && (i += v.size()) < 0)
327  throw index_error();
328  if ((SizeType)i >= v.size())
329  throw index_error();
330  return v[(SizeType)i];
331  }
332  );
333 
334  cl.def("__iter__",
335  [](Vector &v) {
336  return make_iterator<
337  return_value_policy::copy, ItType, ItType, T>(
338  v.begin(), v.end());
339  },
340  keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
341  );
342 }
343 
344 template <typename Vector, typename Class_> auto vector_if_insertion_operator(Class_ &cl, std::string const &name)
345  -> decltype(std::declval<std::ostream&>() << std::declval<typename Vector::value_type>(), void()) {
346  using size_type = typename Vector::size_type;
347 
348  cl.def("__repr__",
349  [name](Vector &v) {
350  std::ostringstream s;
351  s << name << '[';
352  for (size_type i=0; i < v.size(); ++i) {
353  s << v[i];
354  if (i != v.size() - 1)
355  s << ", ";
356  }
357  s << ']';
358  return s.str();
359  },
360  "Return the canonical string representation of this list."
361  );
362 }
363 
364 // Provide the buffer interface for vectors if we have data() and we have a format for it
365 // GCC seems to have "void std::vector<bool>::data()" - doing SFINAE on the existence of data() is insufficient, we need to check it returns an appropriate pointer
366 template <typename Vector, typename = void>
367 struct vector_has_data_and_format : std::false_type {};
368 template <typename Vector>
369 struct vector_has_data_and_format<Vector, enable_if_t<std::is_same<decltype(format_descriptor<typename Vector::value_type>::format(), std::declval<Vector>().data()), typename Vector::value_type*>::value>> : std::true_type {};
370 
371 // Add the buffer interface to a vector
372 template <typename Vector, typename Class_, typename... Args>
374 vector_buffer(Class_& cl) {
375  using T = typename Vector::value_type;
376 
377  static_assert(vector_has_data_and_format<Vector>::value, "There is not an appropriate format descriptor for this vector");
378 
379  // numpy.h declares this for arbitrary types, but it may raise an exception and crash hard at runtime if PYBIND11_NUMPY_DTYPE hasn't been called, so check here
381 
382  cl.def_buffer([](Vector& v) -> buffer_info {
383  return buffer_info(v.data(), static_cast<ssize_t>(sizeof(T)), format_descriptor<T>::format(), 1, {v.size()}, {sizeof(T)});
384  });
385 
386  cl.def(init([](buffer buf) {
387  auto info = buf.request();
388  if (info.ndim != 1 || info.strides[0] % static_cast<ssize_t>(sizeof(T)))
389  throw type_error("Only valid 1D buffers can be copied to a vector");
390  if (!detail::compare_buffer_info<T>::compare(info) || (ssize_t) sizeof(T) != info.itemsize)
391  throw type_error("Format mismatch (Python: " + info.format + " C++: " + format_descriptor<T>::format() + ")");
392 
393  auto vec = std::unique_ptr<Vector>(new Vector());
394  vec->reserve((size_t) info.shape[0]);
395  T *p = static_cast<T*>(info.ptr);
396  ssize_t step = info.strides[0] / static_cast<ssize_t>(sizeof(T));
397  T *end = p + info.shape[0] * step;
398  for (; p != end; p += step)
399  vec->push_back(*p);
400  return vec.release();
401  }));
402 
403  return;
404 }
405 
406 template <typename Vector, typename Class_, typename... Args>
408 
409 NAMESPACE_END(detail)
410 
411 //
412 // std::vector
413 //
414 template <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args>
415 class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, Args&&... args) {
416  using Class_ = class_<Vector, holder_type>;
417 
418  // If the value_type is unregistered (e.g. a converting type) or is itself registered
419  // module-local then make the vector binding module-local as well:
420  using vtype = typename Vector::value_type;
421  auto vtype_info = detail::get_type_info(typeid(vtype));
422  bool local = !vtype_info || vtype_info->module_local;
423 
424  Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
425 
426  // Declare the buffer interface if a buffer_protocol() is passed in
427  detail::vector_buffer<Vector, Class_, Args...>(cl);
428 
429  cl.def(init<>());
430 
431  // Register copy constructor (if possible)
432  detail::vector_if_copy_constructible<Vector, Class_>(cl);
433 
434  // Register comparison-related operators and functions (if possible)
435  detail::vector_if_equal_operator<Vector, Class_>(cl);
436 
437  // Register stream insertion operator (if possible)
438  detail::vector_if_insertion_operator<Vector, Class_>(cl, name);
439 
440  // Modifiers require copyable vector value type
441  detail::vector_modifiers<Vector, Class_>(cl);
442 
443  // Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive
444  detail::vector_accessor<Vector, Class_>(cl);
445 
446  cl.def("__bool__",
447  [](const Vector &v) -> bool {
448  return !v.empty();
449  },
450  "Check whether the list is nonempty"
451  );
452 
453  cl.def("__len__", &Vector::size);
454 
455 
456 
457 
458 #if 0
459  // C++ style functions deprecated, leaving it here as an example
460  cl.def(init<size_type>());
461 
462  cl.def("resize",
463  (void (Vector::*) (size_type count)) & Vector::resize,
464  "changes the number of elements stored");
465 
466  cl.def("erase",
467  [](Vector &v, SizeType i) {
468  if (i >= v.size())
469  throw index_error();
470  v.erase(v.begin() + i);
471  }, "erases element at index ``i``");
472 
473  cl.def("empty", &Vector::empty, "checks whether the container is empty");
474  cl.def("size", &Vector::size, "returns the number of elements");
475  cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end");
476  cl.def("pop_back", &Vector::pop_back, "removes the last element");
477 
478  cl.def("max_size", &Vector::max_size, "returns the maximum possible number of elements");
479  cl.def("reserve", &Vector::reserve, "reserves storage");
480  cl.def("capacity", &Vector::capacity, "returns the number of elements that can be held in currently allocated storage");
481  cl.def("shrink_to_fit", &Vector::shrink_to_fit, "reduces memory usage by freeing unused memory");
482 
483  cl.def("clear", &Vector::clear, "clears the contents");
484  cl.def("swap", &Vector::swap, "swaps the contents");
485 
486  cl.def("front", [](Vector &v) {
487  if (v.size()) return v.front();
488  else throw index_error();
489  }, "access the first element");
490 
491  cl.def("back", [](Vector &v) {
492  if (v.size()) return v.back();
493  else throw index_error();
494  }, "access the last element ");
495 
496 #endif
497 
498  return cl;
499 }
500 
501 
502 
503 //
504 // std::map, std::unordered_map
505 //
506 
507 NAMESPACE_BEGIN(detail)
508 
509 /* Fallback functions */
510 template <typename, typename, typename... Args> void map_if_insertion_operator(const Args &...) { }
511 template <typename, typename, typename... Args> void map_assignment(const Args &...) { }
512 
513 // Map assignment when copy-assignable: just copy the value
514 template <typename Map, typename Class_>
516  using KeyType = typename Map::key_type;
517  using MappedType = typename Map::mapped_type;
518 
519  cl.def("__setitem__",
520  [](Map &m, const KeyType &k, const MappedType &v) {
521  auto it = m.find(k);
522  if (it != m.end()) it->second = v;
523  else m.emplace(k, v);
524  }
525  );
526 }
527 
528 // Not copy-assignable, but still copy-constructible: we can update the value by erasing and reinserting
529 template<typename Map, typename Class_>
533  Class_> &cl) {
534  using KeyType = typename Map::key_type;
535  using MappedType = typename Map::mapped_type;
536 
537  cl.def("__setitem__",
538  [](Map &m, const KeyType &k, const MappedType &v) {
539  // We can't use m[k] = v; because value type might not be default constructable
540  auto r = m.emplace(k, v);
541  if (!r.second) {
542  // value type is not copy assignable so the only way to insert it is to erase it first...
543  m.erase(r.first);
544  m.emplace(k, v);
545  }
546  }
547  );
548 }
549 
550 
551 template <typename Map, typename Class_> auto map_if_insertion_operator(Class_ &cl, std::string const &name)
552 -> decltype(std::declval<std::ostream&>() << std::declval<typename Map::key_type>() << std::declval<typename Map::mapped_type>(), void()) {
553 
554  cl.def("__repr__",
555  [name](Map &m) {
556  std::ostringstream s;
557  s << name << '{';
558  bool f = false;
559  for (auto const &kv : m) {
560  if (f)
561  s << ", ";
562  s << kv.first << ": " << kv.second;
563  f = true;
564  }
565  s << '}';
566  return s.str();
567  },
568  "Return the canonical string representation of this map."
569  );
570 }
571 
572 
573 NAMESPACE_END(detail)
574 
575 template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args>
576 class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&... args) {
577  using KeyType = typename Map::key_type;
578  using MappedType = typename Map::mapped_type;
579  using Class_ = class_<Map, holder_type>;
580 
581  // If either type is a non-module-local bound type then make the map binding non-local as well;
582  // otherwise (e.g. both types are either module-local or converting) the map will be
583  // module-local.
584  auto tinfo = detail::get_type_info(typeid(MappedType));
585  bool local = !tinfo || tinfo->module_local;
586  if (local) {
587  tinfo = detail::get_type_info(typeid(KeyType));
588  local = !tinfo || tinfo->module_local;
589  }
590 
591  Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
592 
593  cl.def(init<>());
594 
595  // Register stream insertion operator (if possible)
596  detail::map_if_insertion_operator<Map, Class_>(cl, name);
597 
598  cl.def("__bool__",
599  [](const Map &m) -> bool { return !m.empty(); },
600  "Check whether the map is nonempty"
601  );
602 
603  cl.def("__iter__",
604  [](Map &m) { return make_key_iterator(m.begin(), m.end()); },
605  keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
606  );
607 
608  cl.def("items",
609  [](Map &m) { return make_iterator(m.begin(), m.end()); },
610  keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
611  );
612 
613  cl.def("__getitem__",
614  [](Map &m, const KeyType &k) -> MappedType & {
615  auto it = m.find(k);
616  if (it == m.end())
617  throw key_error();
618  return it->second;
619  },
620  return_value_policy::reference_internal // ref + keepalive
621  );
622 
623  cl.def("__contains__",
624  [](Map &m, const KeyType &k) -> bool {
625  auto it = m.find(k);
626  if (it == m.end())
627  return false;
628  return true;
629  }
630  );
631 
632  // Assignment provided only if the type is copyable
633  detail::map_assignment<Map, Class_>(cl);
634 
635  cl.def("__delitem__",
636  [](Map &m, const KeyType &k) {
637  auto it = m.find(k);
638  if (it == m.end())
639  throw key_error();
640  m.erase(it);
641  }
642  );
643 
644  cl.def("__len__", &Map::size);
645 
646  return cl;
647 }
648 
iterator make_key_iterator(Iterator first, Sentinel last, Extra &&... extra)
Definition: pybind11.h:1687
Annotation for parent scope.
Definition: attr.h:27
#define PYBIND11_NAMESPACE
Definition: detail/common.h:26
void vector_accessor(enable_if_t< vector_needs_copy< Vector >::value, Class_ > &cl)
Definition: stl_bind.h:319
STL namespace.
void map_assignment(enable_if_t< !std::is_copy_assignable< typename Map::mapped_type >::value &&is_copy_constructible< typename Map::mapped_type >::value, Class_ > &cl)
Definition: stl_bind.h:530
class_< Vector, holder_type > bind_vector(handle scope, std::string const &name, Args &&... args)
Definition: stl_bind.h:415
auto format(const std::locale &loc, const CharT *fmt, const Streamable &tp) -> decltype(to_stream(std::declval< std::basic_ostream< CharT > &>(), fmt, tp), std::basic_string< CharT >
Definition: date.h:5663
void vector_modifiers(enable_if_t< is_copy_constructible< typename Vector::value_type >::value, Class_ > &cl)
Definition: stl_bind.h:113
Information record describing a Python buffer object.
Definition: buffer_info.h:17
detail::initimpl::constructor< Args... > init()
Binds an existing constructor taking arguments Args...
Definition: pybind11.h:1371
#define NAMESPACE_END(name)
Definition: detail/common.h:16
class_< Map, holder_type > bind_map(handle scope, const std::string &name, Args &&... args)
Definition: stl_bind.h:576
Keep patient alive while nurse lives.
Definition: attr.h:45
size_t len_hint(handle h)
Definition: pytypes.h:1368
void vector_if_equal_operator(enable_if_t< is_comparable< Vector >::value, Class_ > &cl)
Definition: stl_bind.h:74
enable_if_t<!detail::any_of< std::is_same< Args, buffer_protocol >... >::value > vector_buffer(Class_ &)
Definition: stl_bind.h:407
Annotation for function names.
Definition: attr.h:33
auto map_if_insertion_operator(Class_ &cl, std::string const &name) -> decltype(std::declval< std::ostream &>()<< std::declval< typename Map::key_type >()<< std::declval< typename Map::mapped_type >(), void())
Definition: stl_bind.h:551
auto vector_if_insertion_operator(Class_ &cl, std::string const &name) -> decltype(std::declval< std::ostream &>()<< std::declval< typename Vector::value_type >(), void())
Definition: stl_bind.h:344
#define NAMESPACE_BEGIN(name)
Definition: detail/common.h:13
void vector_if_copy_constructible(enable_if_t< is_copy_constructible< Vector >::value, Class_ > &cl)
Definition: stl_bind.h:69
iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra)
Makes a python iterator from a first and past-the-end C++ InputIterator.
Definition: pybind11.h:1658
const std::type_info & tinfo
Definition: numpy.h:1091
typename std::enable_if< B, T >::type enable_if_t
from cpp_future import (convenient aliases from C++14/17)
Py_ssize_t ssize_t
Annotation that marks a class as local to the module:
Definition: attr.h:68