pthom / litgen

litgen: a pybind11 automatic generator for humans who like nice code and API documentation. Also a C++ transformer tool

Home Page:https://pthom.github.io/litgen

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

C++ unions

renautomation opened this issue · comments

Hello,
I have code like this:
typedef union u_signalValue_t {
float flt;
int32_t i32;
double dbl;
int64_t i64;
} signalValue_t;
I already overcame the issue related to the usage of "typedef", by pre-processing the code, as suggested here:
#7

So, my pre-processed code is now:
union signalValue_t {
float flt;
int32_t i32;
double dbl;
int64_t i64;
};

however, it seems the the union type is not processed by litgen: I see all other types in the pybind11 C++ code, like enums, classes, structs, etc. except this union.

Any suggestion?

Union types are very, very, C/C++ specific.

There is no such thing as unions in Python: object and base types will always occupy different memory locations.

Solutions:

1/ Either you write a wrapper And use it in the API you want to publish.

class MySignal 
{
  int as_int();
   ...
private:
   signalValue_t xxx;

};

2/ And/or you write a custom caster And give it appropriate methods.

https://pybind11.readthedocs.io/en/stable/advanced/cast/custom.html

Hi, I used the wrapper approach suggested above by ChatGPT. Now, I'm trying to add the original union type in the exclude options, but I don't find the proper option. I only found:
fn_exclude_by_name__regex
class_exclude_by_name__regex
member_exclude_by_name__regex
but of course they don't work because I don't have neither a function nor a class, I have a union.
The problem is that, if I don't exclude it, in the generated code, in the bindings related to the functions and classes that use my union, I find stuff like:
..., py::arg("value") = signalValue_t(), ... (in pybind11_module.cpp)
...value: signalValue_t ... (in init.pyi)

the build process works, but then when I go to Python:
`>>> from MyPythonBindings import *
Traceback (most recent call last):
File "", line 1, in
File "/My/Path/init.py", line 1, in
from MyPythonBindings._MyPythonBindings import * # type: ignore # noqa: F403
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ImportError: arg(): could not convert default argument into a Python object (type not registered yet?). #define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more information.

`

https://github.com/pthom/litgen/blob/226992d4e30be298963fa96e52254e2e45af6477/src/litgen/options.py#L110C1-L118C46

    # Exclude certain functions and methods by a regex on any of their parameter type and/or return type
    # (those should be decorated type)
    # For example:
    #     options.fn_exclude_by_param_type__regex = "^char\s*$|^unsigned\s+char$|Callback$"
    # would exclude all functions having params of type "char *", "unsigned char", "xxxCallback"
    #
    # Note: this is distinct from `fn_params_exclude_types__regex` which removes params
    # from the function signature, but not the function itself.
    fn_exclude_by_param_type__regex: str = ""

ok, I was doing confusion before on what I really needed... I didn't need to exclude the "union" (also because it was already excluded by litgen by default, in fact I opened the issue exactly for this reason.

So, now I found the way to expose union types, and I resume the procedure for eventual future users:

  • wrap the union as described above
  • force the exposed functions to use the wrapped version and not the original union by pre-processing the header via options.srcmlcpp_options.code_preprocess_function
  • exclude the creation of the binding for the union element present into the wrapper, by using options.member_exclude_by_type__regex

Now the bindings are correctly generaed and the wrapped union works s expected. Thanks a lot for your support, @pthom