Skip to content

[QUESTION]: Example for wrapping std::variant #4108

Open
@gabrieldevillers

Description

@gabrieldevillers

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

}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions