Skip to content

How to return a std::tuple wrapped in std::shared_ptr??? #1666

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
lazylazypig opened this issue Jan 13, 2019 · 6 comments
Closed

How to return a std::tuple wrapped in std::shared_ptr??? #1666

lazylazypig opened this issue Jan 13, 2019 · 6 comments

Comments

@lazylazypig
Copy link

lazylazypig commented Jan 13, 2019

Hi, all
I'd like to bind a function that return a std::tuple wrapped in smart pointer (like std::shared_tr). following is my sample code:

C++ Portion

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include
#include
#include

namespace py = pybind11;

using PlateInfo = std::tuple<std::tuple<int, int, int, int>, std::string>;

std::shared_ptr getPlate(bool isOK)
{
if (!isOK) nullptr;
return std::make_shared(std::make_tuple(std::make_tuple(100, 100, 200, 200), "abcdefg"));
}

PYBIND11_MODULE(example, m)
{
m.def("getPlate", &getPlate);
}

the code above can be compile without no error. but, in the python code, it failed :(

Python Portion

import example

plate_info = example.getPlate(True)

it is just a very simple use case, by I got following errors:

Traceback (most recent call last):
File "test.py", line 59, in
plate_info = example.getPlate(True)
TypeError: Unable to convert function return value to a Python type! The signature was
(arg0: bool) -> std::tuple<std::tuple<int,int,int,int>,std::basic_string<char,std::char_traits,std::allocator > >

Did you forget to #include <pybind11/stl.h>? Or <pybind11/complex.h>,
<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic
conversions are optional and require extra headers to be included
when compiling your pybind11 module.

as you seen, I have included the needed header like <pybind11/stl.h>. have i done something wrong? and, how can i fixed it? thanks:)

@haolu23
Copy link

haolu23 commented Feb 1, 2019

have the same question. it is fine to just return a tuple, but not shared_ptr of tuple.

@lazylazypig
Copy link
Author

lazylazypig commented Feb 19, 2019

@haolu23 unfortunately, there seem to be no way for this usage. so i prefer to return std::optional/boost::optional of tuple instead. the code pieces showed bellow:

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#ifdef USE_BOOST_OPTIONAL
#include <boost/optional.hpp>
using boost::optional;
using boost::make_optional;

namespace pybind11 {
namespace detail {
template
struct type_caster<boost::optional> : optional_caster<boost::optional> {};
} // detail
} // pybind11
#else
#include
using std::optional;
#endif

@YannickJadoul
Copy link
Collaborator

As the docs explain, when returning an object with type std::tuple, the contents are copied into a Python tuple, so the std::shared_ptr wouldn't do anything anyway.

If you wish to return an std::tuple object to Python without copying, make it opaque. And in this case, give it std::shared_ptr as holder type.

Relevant docs: https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html#stl-containers

@wojdyr
Copy link
Contributor

wojdyr commented Jul 25, 2020

@YannickJadoul I think it's not about returning object without copying, but about handling pointers.

For example, you can have bindings to a function that returns string by pointer:

m.def("return_none_string", []() -> std::string * { return nullptr; });

but with a pointer to a tuple or pair it will fail to compile:

m.def("return_none_pair", []() -> std::pair<int,int> * { return nullptr; });

Perhaps it's intended, I don't know. tuple_caster doesn't use PYBIND11_TYPE_CASTER() like most of other built-in casters.

@YannickJadoul
Copy link
Collaborator

@wojdyr That's an interesting inconsistency indeed. If you ask me, maybe std::string * shouldn't be allowed, since it suggests something else than what's actually happening (but then None/nullptr is some weird cornercase indeed).

I'm not sure whether this will have been intentional or not, but the only thing I can think of is this: having a function potentially return None means you can't write a, b = return_none_pair() anymore, even though the docstring says it would return a tuple?

Apart from that, it's more likely to be an oversight/detail of how it was implemented, rather than a conscious decision. I guess we could make it consistent, but it would really be low on the list of priorities.

@bstaletic
Copy link
Collaborator

I guess we could make it consistent, but it would really be low on the list of priorities.

That said, pull requests welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants