pybind / pybind/pybind11

[QUESTION]: Example for wrapping std::variant

Open
#4,108 7 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
C++
Stars
18k
Forks
2.3k
Avg merge
5d 17h
Merged PRs (30d)
10

Description

Required prerequisites
Problem description

Hello,

I am evaluating pybind11 and I was able to wrap many things without trouble, until trying to wrap a function taking a std::variant as argument. In the documentation I understand that I do not need to use type_caster because it it seems to me that it is already defined in pybind11/stl.h for std::variant. However I think I am missing something, because I would expect to have to call some py::class_ function specifically for the variant (?).

I found no example for wrapping a std::variant in the documentation or elsewhere on the internet or in pybind's test suite. Sorry if this is actually trivial.

Here is an example code and associated compilation error I have with MSVC:

pybind11\include\pybind11/pybind11.h(167): error C2280: 'pybind11::detail::argument_loader<pybind11::detail::value_and_holder &,MyVariant>::argument_loader(void)': attempting to reference a deleted function
pybind11\include\pybind11\cast.h(1445): note: compiler has generated 'pybind11::detail::argument_loader<pybind11::detail::value_and_holder &,MyVariant>::argument_loader' here
pybind11\include\pybind11\cast.h(1445): note: 'pybind11::detail::argument_loader<pybind11::detail::value_and_holder &,MyVariant>::argument_loader(void)': function was implicitly deleted because a data member 'pybind11::detail::argument_loader<pybind11::detail::value_and_holder &,MyVariant>::argcasters' has either no appropriate default constructor or overload resolution was ambiguous
pybind11\include\pybind11\cast.h(1444): note: see declaration of 'pybind11::detail::argument_loader<pybind11::detail::value_and_holder &,MyVariant>::argcasters'
ybind11\include\pybind11/pybind11.h(99): note: see reference to function template instantiation 'void pybind11::cpp_function::initialize<Ty,R,pybind11::detail::value_and_holder&,MyVariant,pybind11::name,pybind11::is_method,pybind11::sibling,pybind11::detail::is_new_style_constructor>(Func &&,Return (cdecl *)(pybind11::detail::value_and_holder &,MyVariant),const pybind11::name &,const pybind11::is_method &,const pybind11::sibling &,const pybind11::detail::is_new_style_constructor &)' being compiled
with
[
Ty=pybind11::detail::initimpl::constructor::execute::<lambda_4bce0e84265d89e846bdadb006aa47c7>,
R=void,
Func=pybind11::detail::initimpl::constructor::execute::<lambda_4bce0e84265d89e846bdadb006aa47c7>,
Return=void
]
pybind11\include\pybind11/pybind11.h(1557): note: see reference to function template instantiation 'pybind11::cpp_function::cpp_function<Ty,pybind11::name,pybind11::is_method,pybind11::sibling,pybind11::detail::is_new_style_constructor,void>(Func &&,const pybind11::name &,const pybind11::is_method &,const pybind11::sibling &,const pybind11::detail::is_new_style_constructor &)' being compiled
with
[
Ty=pybind11::detail::initimpl::constructor::execute::<lambda_4bce0e84265d89e846bdadb006aa47c7>,
Func=pybind11::detail::initimpl::constructor::execute::<lambda_4bce0e84265d89e846bdadb006aa47c7>
]
pybind11\include\pybind11\detail/init.h(199): note: see reference to function template instantiation 'pybind11::class
&pybind11::class
::def<pybind11::detail::initimpl::constructor::execute::<lambda_4bce0e84265d89e846bdadb006aa47c7>,pybind11::detail::is_new_style_constructor>(const char *,Func &&,const pybind11::detail::is_new_style_constructor &)' being compiled
with
[
Func=pybind11::detail::initimpl::constructor::execute::<lambda_4bce0e84265d89e846bdadb006aa47c7>
]
pybind11\include\pybind11\detail/init.h(200): note: see reference to function template instantiation 'pybind11::class
&pybind11::class
::def<pybind11::detail::initimpl::constructor::execute::<lambda_4bce0e84265d89e846bdadb006aa47c7>,pybind11::detail::is_new_style_constructor>(const char *,Func &&,const pybind11::detail::is_new_style_constructor &)' being compiled
with
[
Func=pybind11::detail::initimpl::constructor::execute::<lambda_4bce0e84265d89e846bdadb006aa47c7>
]
pybind11\include\pybind11/pybind11.h(1594): note: see reference to function template instantiation 'void pybind11::detail::initimpl::constructor::execute<pybind11::class
,,0>(Class &)' being compiled
with
[
Class=pybind11::class

]
pybind11\include\pybind11/pybind11.h(1596): note: see reference to function template instantiation 'void pybind11::detail::initimpl::constructor::execute<pybind11::class_,,0>(Class &)' being compiled
with
[
Class=pybind11::class_
]
pybind_example.cpp(27): note: see reference to function template instantiation 'pybind11::class_ &pybind11::class_::def<MyVariant,>(const pybind11::detail::initimpl::constructor &)' being compiled
pybind_example.cpp(28): note: see reference to function template instantiation 'pybind11::class_ &pybind11::class_::def<MyVariant,>(const pybind11::detail::initimpl::constructor &)' being compiled

Reproducible example code
#include <variant>
#include <vector>

class MyClassA
{
public:
    MyClassA(double x) {}
};

class MyClassB
{
public:
    MyClassB(const std::vector<double>& x) {}
};

using MyVariant = std::variant<MyClassA, MyClassB>;

class MyTestClass
{
public:
    MyTestClass(const MyVariant& variant) {}
};

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
namespace py = pybind11;

PYBIND11_MODULE(MyModule, m) {

    py::class_<MyClassA>(m, "MyClassA")
        .def(py::init<double>());

    py::class_<MyClassB>(m, "MyClassB")
        .def(py::init<std::vector<double>>());

    py::class_<MyTestClass>(m, "MyTestClass")
        .def(py::init<MyVariant>()); // compilation problem here

}
Example code which does not reproduce
#include <variant>

class MyClassA
{
public:
    MyClassA() {}
};

class MyClassB
{
public:
    MyClassB(double x) {}
};

using MyVariant = std::variant<MyClassA, MyClassB>;

class MyTestClass
{
public:
    MyTestClass(const MyVariant& variant) {}
};

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
namespace py = pybind11;

PYBIND11_MODULE(MyModule, m) {

    py::class_<MyClassA>(m, "MyClassA")
        .def(py::init<>());

    py::class_<MyClassB>(m, "MyClassB")
        .def(py::init<double>());

    py::class_<MyTestClass>(m, "MyTestClass")
        .def(py::init<MyVariant>()); // compilation problem here

}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the advanced/cast/stl.html documentation and pybind11/stl.h, then reproduce the supplied MyVariant examples and the MSVC compilation error. Document a working std::variant wrapping example and explain whether additional binding is required, with the documented behavior matching the reproducible cases.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, python
Domain
api, documentation
Issue type
Documentation
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.