06 — Binding template instantiations¶
Source: examples/cookbook/06-templates.
welder's model for templates is annotate the template, bind instantiations (Binding templates). The annotations on the primary template are carried by every instantiation; you pick the concrete types. An instantiation has no identifier of its own, so it needs a name from you — and there are two routes: a namespace-scope alias riding the sweep (recommended — the alias is the name), or a directly-welded instantiation with an explicit name string.
Annotate once¶
template <class T>
struct
[[
=welder::weld(welder::lang::py),
=welder::doc("A single value in a labelled box."),
=welder::tparam("T", "the stored value type")
]]
Box {
std::string label;
T value{};
...
};
template <class T>
[[=welder::weld(welder::lang::py), =welder::doc("Swap the contents of two boxes.")]]
void swap_boxes(Box<T>& a, Box<T>& b);
Route 1 — alias the instantiation, let the sweep bind it¶
members_of(ns) enumerates the class template, never a specialization, so a
namespace-scope alias is how an instantiation enters a weld_namespace sweep —
binding under the alias's name, with the template's weld/doc gating and
documenting it:
namespace boxes {
using IntBox = Box<int>; // ← binds as IntBox
using TextBox = Box<std::string>; // ← binds as TextBox
}
weld::weld_namespace<^^boxes>(m); // no name strings anywhere
The alias may additionally carry weld (the opt-in for a third-party template
you cannot annotate) or weld_as (a verbatim rename); both take precedence over
the template's. Every other mark belongs on the template — see the
guide for
the full rules (duplicates and plain-type aliases are compile errors).
Route 2 — weld the instantiation directly¶
weld::weld_type<boxes::Box<double>>(m, "RealBox");
// A function-template instantiation is reflected with substitute():
weld::weld_function<std::meta::substitute(^^boxes::swap_boxes, {^^int})>(
m, "swap_int_boxes");
Why the explicit name here
has_identifier(^^Box<double>) is false — there is no C++ spelling to derive
a name from, and Python wouldn't accept Box<double> anyway. An alias cannot
help on this route either: a type template parameter dealiases, so by the
time weld_type sees the type the alias is gone. The call-site name (or a
weld_as on the template) is therefore the name; omitting both fails with a
clear message at binding time.
What the check asserts¶
The alias-bound instantiations work independently (IntBox holds an int,
TextBox a str) and the bare template Box is absent; the directly-welded
RealBox works under its verbatim name; the primary template's doc shows up on
all three classes' __doc__; and the substitute()-formed swap_int_boxes
really swaps.