Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Classes and structs

Exclude members and classes

Sometimes, you may want to exclude classes and/or members from the bindings. Look at the example below for instructions:

import litgen
from litgen.demo import litgen_demo

cpp_code = """
    class FooDetails // A class that we want to exclude from the bindings
    {
        // ...
    };

    struct Foo 
    {
        int X = 0, Y = 1;

        FooDetails mDetails = {}; // A member that we would want to exclude from the bindings
    };
"""


options = litgen.LitgenOptions()
options.class_exclude_by_name__regex = r"Details$"
options.member_exclude_by_name__regex = r"Details$"
litgen_demo.demo(options, cpp_code)
Loading...

Default constructor with named params

litgen will automatically generate a default constructor with named params for structs. For classes, you can use options.class_create_default_named_ctor__regex. This constructor is generated only if the class/struct does not provide a default constructor.

See example below:

cpp_code = """
    enum class Options { A, B };

    // A constructor with named params will be created for FooClass, 
    // since options.class_create_default_named_ctor__regex  was filled
    class FooClass { 
      public:
        Options options = Options::A;
        int a = 1;
    };

    // A constructor with named params will be created for FooStruct
    struct FooStruct { int X = 0, Y = 1; };

    // FooStruct has a default constructor, so no constructor with named params will be generated
    struct FooStruct2 {
        FooStruct2();
        int X = 0, Y = 1;
    };
"""
options = litgen.LitgenOptions()
# options.struct_create_default_named_ctor__regex = r".*"
options.class_create_default_named_ctor__regex = r".*"
litgen_demo.demo(options, cpp_code)
Loading...

Expose protected member functions

Relevant portion of the pybind11 manual and of the nanobind manual

Exposing protected member functions requires the creation of a “Publicist” helper class. litgen enables to automate this:

cpp_code = """
class A {
protected:
    int foo() const { return 42; }
};
"""

options = litgen.LitgenOptions()
options.class_expose_protected_methods__regex = "^A$"
litgen_demo.demo(options, cpp_code, show_pydef=True)
Loading...

Overriding virtual methods in Python

Relevant portion of the pybind11 manual and of the nanobind manual

In order to override virtual methods in Python, you need to create of a trampoline class, which can be a bit cumbersome.

litgen can automate this: look at the pybind11 binding code, and at the glue code below.

cpp_code = """
    class Animal {
    public:
        virtual ~Animal() { }
        virtual std::string go(int n_times) = 0;
    };
"""

options = litgen.LitgenOptions()
options.class_override_virtual_methods_in_python__regex = "^Animal$"
litgen_demo.demo(options, cpp_code, show_pydef=True)
Loading...

Note: in the case of nanobind, the glue code will differ a bit. It is shown below:

options.bind_library = litgen.BindLibraryType.nanobind
generated_code = litgen.generate_code(options, cpp_code)
litgen_demo.show_cpp_code(generated_code.glue_code, "Glue code with nanobind")
Loading...

Combining virtual functions and inheritance

Relevant portion of the pybind11 manual and of the nanobind manual

cpp_code = """
    class Animal {
    public:
        virtual std::string go(int n_times) = 0;
        virtual std::string name() { return "unknown"; }
    };

    class Dog : public Animal {
    public:
        std::string go(int n_times) override {
            std::string result;
            for (int i=0; i<n_times; ++i)
                result += bark() + " ";
            return result;
        }
        virtual std::string bark() { return "woof!"; }
    };
"""

options = litgen.LitgenOptions()
options.class_override_virtual_methods_in_python__regex = "^Animal$|^Dog$"
litgen_demo.demo(options, cpp_code, show_pydef=True)
Loading...

Note: in the case of nanobind, the glue code will differ a bit. It is shown below:

options.bind_library = litgen.BindLibraryType.nanobind
generated_code = litgen.generate_code(options, cpp_code)
litgen_demo.show_cpp_code(generated_code.glue_code, "Glue code with nanobind")
Loading...

Operator overloading

litgen is able to automatically transform C++ numerical operators into their corresponding dunder function in Python.

Overloading addition, substraction, etc.

See example below:

cpp_code = """
        struct IntWrapper
        {
            int value;
            IntWrapper(int v) : value(v) {}

            // arithmetic operators
            IntWrapper operator+(IntWrapper b) { return IntWrapper{ value + b.value}; }
            IntWrapper operator-(IntWrapper b) { return IntWrapper{ value - b.value }; }

            // Unary minus operator
            IntWrapper operator-() { return IntWrapper{ -value }; }

            // Comparison operator
            bool operator<(IntWrapper b) { return value < b.value; }

            // Two overload of the += operator
            IntWrapper operator+=(IntWrapper b) { value += b.value; return *this; }
            IntWrapper operator+=(int b) { value += b; return *this; }

            // Two overload of the call operator, with different results
            int operator()(IntWrapper b) { return value * b.value + 2; }
            int operator()(int b) { return value * b + 3; }
        };
"""

options = litgen.LitgenOptions()
litgen_demo.demo(options, cpp_code, height=60)
Loading...

Overloading comparisons with the spaceship operator

cpp_code = """
    struct Point
    {
        int x;
        int y;
        auto operator<=>(const Point&) const = default;
    };
"""
options = litgen.LitgenOptions()
litgen_demo.demo(options, cpp_code)
Loading...

Dynamic attributes

Relevant portion of the pybind11 manual and of the nanobind manual

The python class Pet below will be able to pick up new attributes dynamically:

cpp_code = """
struct Pet {
    Pet(const std::string &name) : name(name) { }
    std::string name;
};
"""
options = litgen.LitgenOptions()
options.class_dynamic_attributes__regex = "^Pet$"
litgen_demo.demo(options, cpp_code, show_pydef=True)
Loading...

Copy and Deep copy

Relevant portion of the pybind11 manual. The principle is the same for nanobind.

See below for instructions on how to add support for copy and deepcopy.

cpp_code = """
    struct Foo { std::vector<int> values; };
    struct Foo2 { 
        Foo foo1 = Foo();
        Foo foo2 = Foo();
    };
"""

options = litgen.LitgenOptions()
options.class_copy__regex = "^Foo$|^Foo2$"
options.class_deep_copy__regex = "^Foo2$"
options.class_copy_add_info_in_stub = True
litgen_demo.demo(options, cpp_code)
Loading...

Iterable classes

It is possible to make custom container classes iterable in python. See example below:

cpp_code = """
class MyContainer
{
public:
    float operator[](int idx);

    // We need to have defined begin(), end(), and size() to make the class iterable
    iterator begin(); // This function is excluded from the bindings (see options.fn_exclude_by_name__regex)
    iterator end();   // This function is excluded from the bindings (see options.fn_exclude_by_name__regex)
    size_t size();    // This function is also published as __len__
private:
    std::vector<float> values;
};
"""

options = litgen.LitgenOptions()
options.class_iterables_infos.add_iterable_class("^MyContainer$", "float")
options.fn_exclude_by_name__regex = "^begin$|^end$"
litgen_demo.demo(options, cpp_code, show_pydef=True)
Loading...

Numeric C array members

If a struct/class stores a numeric C array member, it will be exposed as a modifiable numpy array.

cpp_code = """
struct Foo {  int values[4]; };
"""
options = litgen.LitgenOptions()
# options.member_numeric_c_array_replace__regex = r".*"  # this is the default
litgen_demo.demo(options, cpp_code, show_pydef=True)
Loading...

Inner class or enum

litgen handles inner classes or enum and correctly nest them in their host class:

cpp_code = """
    struct Foo
    {
        enum class Choice { A, B };
        int HandleChoice(Choice value = Choice::A) { return 0; }
    };
"""
options = litgen.LitgenOptions()
litgen_demo.demo(options, cpp_code)
Loading...