blob: c59fbcfcb083a3b00a614ebf838fa3c4bad5280c [file] [log] [blame]
Wenzel Jakob38bd7112015-07-05 20:05:44 +02001/*
2 pybind/cast.h: Partial template specializations to cast between
3 C++ and Python types
4
5 Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
6
7 All rights reserved. Use of this source code is governed by a
8 BSD-style license that can be found in the LICENSE file.
9*/
10
Wenzel Jakobbd4a5292015-07-11 17:41:48 +020011#pragma once
Wenzel Jakob38bd7112015-07-05 20:05:44 +020012
Wenzel Jakobbd4a5292015-07-11 17:41:48 +020013#include <pybind/pytypes.h>
Wenzel Jakobbd4a5292015-07-11 17:41:48 +020014#include <pybind/typeid.h>
Wenzel Jakob38bd7112015-07-05 20:05:44 +020015#include <array>
16
17NAMESPACE_BEGIN(pybind)
18NAMESPACE_BEGIN(detail)
19
20/// Generic type caster for objects stored on the heap
21template <typename type> class type_caster {
22public:
23 typedef instance<type> instance_type;
24
25 static std::string name() { return type_id<type>(); }
26
27 type_caster() {
28 auto const& registered_types = get_internals().registered_types;
29 auto it = registered_types.find(type_id<type>());
30 if (it != registered_types.end())
31 typeinfo = &it->second;
32 }
33
34 bool load(PyObject *src, bool convert) {
35 if (src == nullptr || typeinfo == nullptr)
36 return false;
37 if (PyType_IsSubtype(Py_TYPE(src), typeinfo->type)) {
38 value = ((instance_type *) src)->value;
39 return true;
40 }
41 if (convert) {
42 for (auto &converter : typeinfo->implicit_conversions) {
43 temp = object(converter(src, typeinfo->type), false);
44 if (load(temp.ptr(), false))
45 return true;
46 }
47 }
48 return false;
49 }
50
51 static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
52 if (policy == return_value_policy::automatic)
53 policy = return_value_policy::copy;
54 return cast(&src, policy, parent);
55 }
56
57 static PyObject *cast(const type *_src, return_value_policy policy, PyObject *parent) {
58 type *src = const_cast<type *>(_src);
59 if (src == nullptr) {
60 Py_INCREF(Py_None);
61 return Py_None;
62 }
63 // avoid an issue with internal references matching their parent's address
Wenzel Jakobd4258ba2015-07-26 16:33:49 +020064 bool dont_cache = policy == return_value_policy::reference_internal &&
65 parent && ((instance<void> *) parent)->value == (void *) src;
Wenzel Jakob38bd7112015-07-05 20:05:44 +020066 auto& internals = get_internals();
67 auto it_instance = internals.registered_instances.find(src);
68 if (it_instance != internals.registered_instances.end() && !dont_cache) {
69 PyObject *inst = it_instance->second;
70 Py_INCREF(inst);
71 return inst;
72 }
73 auto it = internals.registered_types.find(type_id<type>());
74 if (it == internals.registered_types.end()) {
75 std::string msg = std::string("Unregistered type : ") + type_id<type>();
76 PyErr_SetString(PyExc_TypeError, msg.c_str());
77 return nullptr;
78 }
79 auto &type_info = it->second;
80 instance_type *inst = (instance_type *) PyType_GenericAlloc(type_info.type, 0);
81 inst->value = src;
82 inst->owned = true;
83 inst->parent = nullptr;
84 if (policy == return_value_policy::automatic)
85 policy = return_value_policy::take_ownership;
86 handle_return_value_policy<type>(inst, policy, parent);
87 PyObject *inst_pyobj = (PyObject *) inst;
88 type_info.init_holder(inst_pyobj);
89 if (!dont_cache)
90 internals.registered_instances[inst->value] = inst_pyobj;
91 return inst_pyobj;
92 }
93
94 template <class T, typename std::enable_if<std::is_copy_constructible<T>::value, int>::type = 0>
95 static void handle_return_value_policy(instance<T> *inst, return_value_policy policy, PyObject *parent) {
96 if (policy == return_value_policy::copy) {
97 inst->value = new T(*(inst->value));
98 } else if (policy == return_value_policy::reference) {
99 inst->owned = false;
100 } else if (policy == return_value_policy::reference_internal) {
101 inst->owned = false;
102 inst->parent = parent;
103 Py_XINCREF(parent);
104 }
105 }
106
107 template <class T, typename std::enable_if<!std::is_copy_constructible<T>::value, int>::type = 0>
108 static void handle_return_value_policy(instance<T> *inst, return_value_policy policy, PyObject *parent) {
109 if (policy == return_value_policy::copy) {
110 throw cast_error("return_value_policy = copy, but the object is non-copyable!");
111 } else if (policy == return_value_policy::reference) {
112 inst->owned = false;
113 } else if (policy == return_value_policy::reference_internal) {
114 inst->owned = false;
115 inst->parent = parent;
116 Py_XINCREF(parent);
117 }
118 }
119
120 operator type*() { return value; }
121 operator type&() { return *value; }
122protected:
123 type *value = nullptr;
124 const type_info *typeinfo = nullptr;
125 object temp;
126};
127
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200128#define PYBIND_TYPE_CASTER(type, py_name) \
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200129 protected: \
130 type value; \
131 public: \
132 static std::string name() { return py_name; } \
133 static PyObject *cast(const type *src, return_value_policy policy, PyObject *parent) { \
134 return cast(*src, policy, parent); \
135 } \
136 operator type*() { return &value; } \
137 operator type&() { return value; } \
138
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200139#define PYBIND_TYPE_CASTER_NUMBER(type, py_type, from_type, to_pytype) \
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200140 template <> class type_caster<type> { \
141 public: \
142 bool load(PyObject *src, bool) { \
143 value = (type) from_type(src); \
144 if (value == (type) -1 && PyErr_Occurred()) { \
145 PyErr_Clear(); \
146 return false; \
147 } \
148 return true; \
149 } \
150 static PyObject *cast(type src, return_value_policy /* policy */, PyObject * /* parent */) { \
151 return to_pytype((py_type) src); \
152 } \
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200153 PYBIND_TYPE_CASTER(type, #type); \
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200154 };
155
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200156PYBIND_TYPE_CASTER_NUMBER(int32_t, long, PyLong_AsLong, PyLong_FromLong)
157PYBIND_TYPE_CASTER_NUMBER(uint32_t, unsigned long, PyLong_AsUnsignedLong, PyLong_FromUnsignedLong)
158PYBIND_TYPE_CASTER_NUMBER(int64_t, PY_LONG_LONG, PyLong_AsLongLong, PyLong_FromLongLong)
159PYBIND_TYPE_CASTER_NUMBER(uint64_t, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong, PyLong_FromUnsignedLongLong)
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200160
161#if defined(__APPLE__) // size_t/ssize_t are separate types on Mac OS X
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200162PYBIND_TYPE_CASTER_NUMBER(ssize_t, Py_ssize_t, PyLong_AsSsize_t, PyLong_FromSsize_t)
163PYBIND_TYPE_CASTER_NUMBER(size_t, size_t, PyLong_AsSize_t, PyLong_FromSize_t)
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200164#endif
165
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200166PYBIND_TYPE_CASTER_NUMBER(float, float, PyFloat_AsDouble, PyFloat_FromDouble)
167PYBIND_TYPE_CASTER_NUMBER(double, double, PyFloat_AsDouble, PyFloat_FromDouble)
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200168
Wenzel Jakob281aa0e2015-07-30 15:29:00 +0200169template <> class type_caster<void_type> {
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200170public:
171 bool load(PyObject *, bool) { return true; }
Wenzel Jakob281aa0e2015-07-30 15:29:00 +0200172 static PyObject *cast(void_type, return_value_policy /* policy */, PyObject * /* parent */) {
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200173 Py_INCREF(Py_None);
174 return Py_None;
175 }
Wenzel Jakob281aa0e2015-07-30 15:29:00 +0200176 PYBIND_TYPE_CASTER(void_type, "None");
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200177};
178
179template <> class type_caster<bool> {
180public:
181 bool load(PyObject *src, bool) {
182 if (src == Py_True) { value = true; return true; }
183 else if (src == Py_False) { value = false; return true; }
184 else return false;
185 }
186 static PyObject *cast(bool src, return_value_policy /* policy */, PyObject * /* parent */) {
187 PyObject *result = src ? Py_True : Py_False;
188 Py_INCREF(result);
189 return result;
190 }
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200191 PYBIND_TYPE_CASTER(bool, "bool");
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200192};
193
194template <> class type_caster<std::string> {
195public:
196 bool load(PyObject *src, bool) {
197 const char *ptr = PyUnicode_AsUTF8(src);
198 if (!ptr) { PyErr_Clear(); return false; }
199 value = std::string(ptr);
200 return true;
201 }
202 static PyObject *cast(const std::string &src, return_value_policy /* policy */, PyObject * /* parent */) {
203 return PyUnicode_FromString(src.c_str());
204 }
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200205 PYBIND_TYPE_CASTER(std::string, "str");
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200206};
207
Wenzel Jakob2ac80e72015-07-22 00:59:01 +0200208#ifdef HAVE_WCHAR_H
209template <> class type_caster<std::wstring> {
210public:
211 bool load(PyObject *src, bool) {
212 const wchar_t *ptr = PyUnicode_AsWideCharString(src, nullptr);
213 if (!ptr) { PyErr_Clear(); return false; }
214 value = std::wstring(ptr);
215 return true;
216 }
217 static PyObject *cast(const std::wstring &src, return_value_policy /* policy */, PyObject * /* parent */) {
218 return PyUnicode_FromWideChar(src.c_str(), src.length());
219 }
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200220 PYBIND_TYPE_CASTER(std::wstring, "wstr");
Wenzel Jakob2ac80e72015-07-22 00:59:01 +0200221};
222#endif
223
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200224template <> class type_caster<char> {
225public:
226 bool load(PyObject *src, bool) {
227 char *ptr = PyUnicode_AsUTF8(src);
228 if (!ptr) { PyErr_Clear(); return false; }
229 value = ptr;
230 return true;
231 }
232
233 static PyObject *cast(const char *src, return_value_policy /* policy */, PyObject * /* parent */) {
234 return PyUnicode_FromString(src);
235 }
236
237 static PyObject *cast(char src, return_value_policy /* policy */, PyObject * /* parent */) {
238 char str[2] = { src, '\0' };
239 return PyUnicode_DecodeLatin1(str, 1, nullptr);
240 }
241
242 static std::string name() { return "str"; }
243
244 operator char*() { return value; }
245 operator char() { return *value; }
246protected:
247 char *value;
248};
249
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200250template <typename T1, typename T2> class type_caster<std::pair<T1, T2>> {
251 typedef std::pair<T1, T2> type;
252public:
253 bool load(PyObject *src, bool convert) {
254 if (!PyTuple_Check(src) || PyTuple_Size(src) != 2)
255 return false;
256 if (!first.load(PyTuple_GetItem(src, 0), convert))
257 return false;
258 return second.load(PyTuple_GetItem(src, 1), convert);
259 }
260
261 static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
Wenzel Jakob281aa0e2015-07-30 15:29:00 +0200262 PyObject *o1 = type_caster<typename decay<T1>::type>::cast(src.first, policy, parent);
263 PyObject *o2 = type_caster<typename decay<T2>::type>::cast(src.second, policy, parent);
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200264 if (!o1 || !o2) {
265 Py_XDECREF(o1);
266 Py_XDECREF(o2);
267 return nullptr;
268 }
269 PyObject *tuple = PyTuple_New(2);
270 PyTuple_SetItem(tuple, 0, o1);
271 PyTuple_SetItem(tuple, 1, o2);
272 return tuple;
273 }
274
275 static std::string name() {
276 return "(" + type_caster<T1>::name() + ", " + type_caster<T2>::name() + ")";
277 }
278
279 operator type() {
280 return type(first, second);
281 }
282protected:
Wenzel Jakob281aa0e2015-07-30 15:29:00 +0200283 type_caster<typename decay<T1>::type> first;
284 type_caster<typename decay<T2>::type> second;
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200285};
286
Wenzel Jakob281aa0e2015-07-30 15:29:00 +0200287template <typename... Tuple> class type_caster<std::tuple<Tuple...>> {
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200288 typedef std::tuple<Tuple...> type;
289public:
290 enum { size = sizeof...(Tuple) };
291
292 bool load(PyObject *src, bool convert) {
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200293 return load(src, convert, typename make_index_sequence<sizeof...(Tuple)>::type());
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200294 }
295
296 static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200297 return cast(src, policy, parent, typename make_index_sequence<size>::type());
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200298 }
299
Wenzel Jakoba576e6a2015-07-29 17:51:54 +0200300 static std::string name(const char **keywords = nullptr, const char **values = nullptr) {
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200301 std::array<std::string, size> names {{
Wenzel Jakob281aa0e2015-07-30 15:29:00 +0200302 type_caster<typename decay<Tuple>::type>::name()...
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200303 }};
304 std::string result("(");
305 int counter = 0;
306 for (auto const &name : names) {
Wenzel Jakoba576e6a2015-07-29 17:51:54 +0200307 if (keywords && keywords[counter]) {
308 result += keywords[counter];
309 result += " : ";
310 }
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200311 result += name;
Wenzel Jakoba576e6a2015-07-29 17:51:54 +0200312 if (values && values[counter]) {
313 result += " = ";
314 result += values[counter];
315 }
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200316 if (++counter < size)
317 result += ", ";
318 }
319 result += ")";
320 return result;
321 }
322
Wenzel Jakoba576e6a2015-07-29 17:51:54 +0200323 template <typename ReturnValue, typename Func> typename std::enable_if<!std::is_void<ReturnValue>::value, ReturnValue>::type call(Func &&f) {
324 return call<ReturnValue>(std::forward<Func>(f), typename make_index_sequence<sizeof...(Tuple)>::type());
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200325 }
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200326
Wenzel Jakob281aa0e2015-07-30 15:29:00 +0200327 template <typename ReturnValue, typename Func> typename std::enable_if<std::is_void<ReturnValue>::value, void_type>::type call(Func &&f) {
Wenzel Jakoba576e6a2015-07-29 17:51:54 +0200328 call<ReturnValue>(std::forward<Func>(f), typename make_index_sequence<sizeof...(Tuple)>::type());
Wenzel Jakob281aa0e2015-07-30 15:29:00 +0200329 return void_type();
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200330 }
331
332 operator type() {
333 return cast(typename make_index_sequence<sizeof...(Tuple)>::type());
334 }
335
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200336protected:
Wenzel Jakoba576e6a2015-07-29 17:51:54 +0200337 template <typename ReturnValue, typename Func, size_t ... Index> ReturnValue call(Func &&f, index_sequence<Index...>) {
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200338 return f((Tuple) std::get<Index>(value)...);
339 }
340
341 template <size_t ... Index> type cast(index_sequence<Index...>) {
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200342 return type((Tuple) std::get<Index>(value)...);
343 }
344
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200345 template <size_t ... Indices> bool load(PyObject *src, bool convert, index_sequence<Indices...>) {
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200346 if (!PyTuple_Check(src))
347 return false;
348 if (PyTuple_Size(src) != size)
349 return false;
350 std::array<bool, size> results {{
Wenzel Jakob281aa0e2015-07-30 15:29:00 +0200351 (PyTuple_GET_ITEM(src, Indices) != nullptr ? std::get<Indices>(value).load(PyTuple_GET_ITEM(src, Indices), convert) : false)...
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200352 }};
Wenzel Jakob281aa0e2015-07-30 15:29:00 +0200353 (void) convert; /* avoid a warning when the tuple is empty */
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200354 for (bool r : results)
355 if (!r)
356 return false;
357 return true;
358 }
359
360 /* Implementation: Convert a C++ tuple into a Python tuple */
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200361 template <size_t ... Indices> static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent, index_sequence<Indices...>) {
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200362 std::array<PyObject *, size> results {{
Wenzel Jakob281aa0e2015-07-30 15:29:00 +0200363 type_caster<typename decay<Tuple>::type>::cast(std::get<Indices>(src), policy, parent)...
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200364 }};
365 bool success = true;
366 for (auto result : results)
367 if (result == nullptr)
368 success = false;
369 if (success) {
370 PyObject *tuple = PyTuple_New(size);
371 int counter = 0;
372 for (auto result : results)
373 PyTuple_SetItem(tuple, counter++, result);
374 return tuple;
375 } else {
376 for (auto result : results) {
377 Py_XDECREF(result);
378 }
379 return nullptr;
380 }
381 }
382
383protected:
Wenzel Jakob281aa0e2015-07-30 15:29:00 +0200384 std::tuple<type_caster<typename decay<Tuple>::type>...> value;
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200385};
386
387/// Type caster for holder types like std::shared_ptr, etc.
388template <typename type, typename holder_type> class type_caster_holder : public type_caster<type> {
389public:
390 typedef type_caster<type> parent;
391 bool load(PyObject *src, bool convert) {
392 if (!parent::load(src, convert))
393 return false;
394 holder = holder_type(parent::value);
395 return true;
396 }
397 explicit operator type*() { return this->value; }
398 explicit operator type&() { return *(this->value); }
399 explicit operator holder_type&() { return holder; }
400 explicit operator holder_type*() { return &holder; }
401protected:
402 holder_type holder;
403};
404
405template <> class type_caster<handle> {
406public:
407 bool load(PyObject *src) {
408 value = handle(src);
409 return true;
410 }
411 static PyObject *cast(const handle &src, return_value_policy /* policy */, PyObject * /* parent */) {
412 src.inc_ref();
413 return (PyObject *) src.ptr();
414 }
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200415 PYBIND_TYPE_CASTER(handle, "handle");
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200416};
417
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200418#define PYBIND_TYPE_CASTER_PYTYPE(name) \
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200419 template <> class type_caster<name> { \
420 public: \
421 bool load(PyObject *src, bool) { value = name(src, true); return true; } \
422 static PyObject *cast(const name &src, return_value_policy /* policy */, PyObject * /* parent */) { \
423 src.inc_ref(); return (PyObject *) src.ptr(); \
424 } \
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200425 PYBIND_TYPE_CASTER(name, #name); \
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200426 };
427
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200428PYBIND_TYPE_CASTER_PYTYPE(object) PYBIND_TYPE_CASTER_PYTYPE(buffer)
429PYBIND_TYPE_CASTER_PYTYPE(capsule) PYBIND_TYPE_CASTER_PYTYPE(dict)
430PYBIND_TYPE_CASTER_PYTYPE(float_) PYBIND_TYPE_CASTER_PYTYPE(int_)
431PYBIND_TYPE_CASTER_PYTYPE(list) PYBIND_TYPE_CASTER_PYTYPE(slice)
432PYBIND_TYPE_CASTER_PYTYPE(tuple) PYBIND_TYPE_CASTER_PYTYPE(function)
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200433
434NAMESPACE_END(detail)
435
436template <typename T> inline T cast(PyObject *object) {
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200437 detail::type_caster<typename detail::decay<T>::type> conv;
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200438 if (!conv.load(object, true))
439 throw cast_error("Unable to cast Python object to C++ type");
440 return conv;
441}
442
443template <typename T> inline object cast(const T &value, return_value_policy policy = return_value_policy::automatic, PyObject *parent = nullptr) {
444 if (policy == return_value_policy::automatic)
445 policy = std::is_pointer<T>::value ? return_value_policy::take_ownership : return_value_policy::copy;
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200446 return object(detail::type_caster<typename detail::decay<T>::type>::cast(value, policy, parent), false);
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200447}
448
449template <typename T> inline T handle::cast() { return pybind::cast<T>(m_ptr); }
450
Wenzel Jakob281aa0e2015-07-30 15:29:00 +0200451template <typename... Args> inline object handle::call(Args&&... args_) {
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200452 const size_t size = sizeof...(Args);
453 std::array<PyObject *, size> args{
Wenzel Jakobd4258ba2015-07-26 16:33:49 +0200454 { detail::type_caster<typename detail::decay<Args>::type>::cast(
Wenzel Jakob38bd7112015-07-05 20:05:44 +0200455 std::forward<Args>(args_), return_value_policy::automatic, nullptr)... }
456 };
457 bool fail = false;
458 for (auto result : args)
459 if (result == nullptr)
460 fail = true;
461 if (fail) {
462 for (auto result : args) {
463 Py_XDECREF(result);
464 }
465 throw cast_error("handle::call(): unable to convert input arguments to Python objects");
466 }
467 PyObject *tuple = PyTuple_New(size);
468 int counter = 0;
469 for (auto result : args)
470 PyTuple_SetItem(tuple, counter++, result);
471 PyObject *result = PyObject_CallObject(m_ptr, tuple);
472 Py_DECREF(tuple);
473 return object(result, false);
474}
475
476NAMESPACE_END(pybind)