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.

Template classes and functions

litgen provides advanced support for template classes and functions. Refer to the examples below.

Template Functions

Relevant portion of the pybind11 manual and of the nanobind manual

litgen can instantiate template functions for a customizable range of types.

Export template functions with an @overload decorator

Consider the example below. If we try to generate code from it, litgen will complain that this template function is unhandled:

cpp_code = """
    template<typename T> T MaxValue(const std::vector<T>& values);
"""

import litgen
from litgen.demo import litgen_demo

options = litgen.LitgenOptions()
generated_code = litgen.generate_code(options, cpp_code)
Warning: (LitgenTemplateFunctionIgnore) Ignoring template function MaxValue. You might need to set LitgenOptions.fn_template_options
While parsing a "function_decl", corresponding to this C++ code:
Position:2:5
        template<typename T> T MaxValue(const std::vector<T>& values);
        ^
Warning: (LitgenTemplateFunctionIgnore) Ignoring template function MaxValue. You might need to set LitgenOptions.fn_template_options
While parsing a "function_decl", corresponding to this C++ code:
Position:2:5
        template<typename T> T MaxValue(const std::vector<T>& values);
        ^

If we add some information about how we want to specialize the function, then litgen will correctly output the bindings, and it will add an @overload decorator to the python functions.

options.fn_template_options.add_specialization("^MaxValue$", ["int", "float"], add_suffix_to_function_name=False)

litgen_demo.demo(options, cpp_code)
Loading...

Export template functions with a suffix

Instead of using @overload, we can give different names to the python functions:

cpp_code = """
    template<typename T> voi LogValue(const std::string& label, const T& value);
"""
options = litgen.LitgenOptions()
options.fn_template_options.add_specialization("^LogValue$", ["int", "float"], add_suffix_to_function_name=True)
litgen_demo.demo(options, cpp_code)
Loading...

Template classes

Introduction

Relevant portion of the pybind11 manual and of the nanobind manual

litgen handles template classes instantiation in a sophisticated way.

In the example below, we set the following options:

type replacements

We set an option for type name replacements, so that ImGuiConfig will be exposed as Config in python:

    options.type_replacements.add_last_replacement(r"ImGui([A-Z][a-zA-Z0-9]*)", r"\1")

class specialization

  • We tell litgen to instantiate ImVector for ImGuiConfig, float *, and int32_t.

  • We also tell it to emit a synonym (ImVector_Int32 = ImVector_int) in the python stub.

    options.class_template_options.add_specialization(
        "ImVector",  # which class do we want to specialize
        ["ImGuiConfig", "float *", "int32_t"],  # for which types
        ["Int32=uint32_t"]  # With which synonyms
        )

Notes

  • The member Foo::Configs will be exposed with the correct python type (ImVector_Config)

  • The member Foo::IntValues will not be published, since ImVector<int> is not published

  • litgen will emit a warning about the missing specialization for int

Example of template class instantiation

cpp_code = """

    struct ImGuiConfig { /* implementation not shown here */ };

    template<typename T>
    struct ImVector
    {
        // Implementation not shown here
    private:
        T* data;
    };

    struct Foo
    {
        ImVector<ImGuiConfig> Configs; // This member will be added to the bindings
        ImVector<int> IntValues;       // This member will be excluded from the bindings, since ImVector<int> is not published!
    };
"""

options = litgen.LitgenOptions()
options.type_replacements.add_last_replacement(r"ImGui([A-Z][a-zA-Z0-9]*)", r"\1")  # Remove prefix ImGui from exposed type
options.class_template_options.add_specialization(
    "ImVector",                             # which class do we want to specialize
    ["ImGuiConfig", "float *", "int32_t"],  # for which types
    ["Int32=uint32_t"],                     # With which synonyms
)
litgen_demo.demo(options, cpp_code)

# Note: the warnings below are normal, since we did not specialize ImVector<int> (they can be filtered out, see below)
Warning: (Undefined) Excluding template type ImVector<int> because its specialization for `int` is not handled
While parsing a "type", corresponding to this C++ code:
Position:16:9
Warning: (Undefined) Excluding template type ImVector<int> because its specialization for `int` is not handled
While parsing a "type", corresponding to this C++ code:
Position:16:9
Warning: (Undefined) Excluding template type ImVector<int> because its specialization for `int` is not handled
While parsing a "type", corresponding to this C++ code:
Position:16:9
Warning: (Undefined) Excluding template type ImVector<int> because its specialization for `int` is not handled
While parsing a "type", corresponding to this C++ code:
Position:16:9
Warning: (Undefined) Excluding template type ImVector<int> because its specialization for `int` is not handled
While parsing a "type", corresponding to this C++ code:
Position:16:9
Warning: (Undefined) Excluding template type ImVector<int> because its specialization for `int` is not handled
While parsing a "type", corresponding to this C++ code:
Position:16:9
Loading...

Suppress template class warnings

You can ask litgen to ignore the warnings concerning the missing specialization:

# tell litgen to ignore warnings that contain "Excluding template type ImVector<int>"
options.srcmlcpp_options.ignored_warning_parts.append("Excluding template type ImVector<int>")
# the following line emits a warning that is ignored
generated_code = litgen.generate_code(options, cpp_code)