0

I'm curious if there's a way to avoid repeating myself. I have several classes that are not related by parentage:

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

namespace py = pybind11;

class Foo {
  public:
    Foo(int x)
        : x(x)
    {}

    int x;
};

class Bar {
  public:
    Bar(int y)
        : y(y)
    {}

    int y;
};

using FooBarType = std::variant<Foo, Bar>;

PYBIND11_MODULE(my_module, m)
{
    py::class_<Foo>(m, "Foo")
        .def(py::init<int>())
        .def_readwrite("x", &Foo::x);

    py::class_<Bar>(m, "Bar")
        .def(py::init<int>())
        .def_readwrite("y", &Bar::y);
}

And my Python code:

from typing import TypeAlias

from my_moduleimport Foo, Bar

FooBarType: TypeAlias = Foo | Bar

def check_foo_bar(value: FooBarType, expected: int):
    if isinstance(value, Foo):
        assert value.x == expected
    elif isinstance(value, Bar):
        assert value.y == expected
    else:
        raise ValueError(f"Unknown type: {type(value)}")

def test_foo_bar():
    foo: FooBarType = Foo(1)
    bar: FooBarType = Bar(2)
    check_foo_bar(foo, 1)
    check_foo_bar(bar, 2)

I'm trying to create a binding to using FooBarType = std::variant<Foo, Bar> so I don't have to define FooBarType: TypeAlias = Foo | Bar.

I've tried using pybind11::type::of:

m.def("FooBarType", py::type::of<FooBarType>());

But that blows up with

In file included from test.cpp:4:
In file included from /home/user/work/external/pybind11/include/pybind11/operators.h:12:
In file included from /home/user/work/external/pybind11/include/pybind11/pybind11.h:13:
In file included from /home/user/work/external/pybind11/include/pybind11/detail/class.h:12:
In file included from /home/user/work/external/pybind11/include/pybind11/attr.h:14:
/home/user/work/external/pybind11/include/pybind11/cast.h:1646:5: error: static_assert failed due to requirement 'std::is_base_of<pybind11::detail::type_caster_generic, pybind11::detail::type_caster<std::variant<Foo, Bar>, void>>::value' "py::type::of<T> only supports the case where T is a registered C++ types."
    static_assert(std::is_base_of<detail::type_caster_generic, detail::make_caster<T>>::value,
    ^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/user/work/external/pybind11/include/pybind11/pytypes.h:1392:27: note: in instantiation of function template specialization 'pybind11::type::handle_of<std::variant<Foo, Bar>>' requested here
        return type(type::handle_of<T>(), borrowed_t{});
                          ^
test.cpp:125:35: note: in instantiation of function template specialization 'pybind11::type::of<std::variant<Foo, Bar>>' requested here
    m.def("FooBarType", py::type::of<FooBarType>());
                                  ^
In file included from test.cpp:4:
In file included from /home/user/work/external/pybind11/include/pybind11/operators.h:12:
In file included from /home/user/work/external/pybind11/include/pybind11/pybind11.h:13:
In file included from /home/user/work/external/pybind11/include/pybind11/detail/class.h:12:
In file included from /home/user/work/external/pybind11/include/pybind11/attr.h:13:
/home/user/work/external/pybind11/include/pybind11/detail/common.h:867:49: error: reference to overloaded function could not be resolved; did you mean to call it?
    using type = typename remove_class<decltype(&F::operator())>::type;

Any help is appreciated.

Cheers!

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.