template<class B>
requires {
{ B::language } -> std::convertible_to<lang>;
typename B::module_type;
} &&
requires(typename B::module_type& m, const char* s,
std::remove_cvref_t<decltype(B::open_module(
std::declval<typename B::module_type&>()))> session) {
{ B::open_module(m) };
{ B::add_submodule(m, s) } -> std::same_as<typename B::module_type>;
B::set_module_doc(m, s);
B::close_module(m, session);
{ B::special_method_name(^^int) } -> std::convertible_to<const char*>;
B::template add_function<std::array<std::meta::info, 1>{^^int},
B::template add_variable<^^int, detail::any_type>(m, session);
} &&
requires(typename B::template class_handle_type<detail::any_type>& cls,
typename B::template enum_handle_type<detail::any_enum>& en) {
std::array<std::meta::info, 0>{}, false,
false>(cls);
B::template add_field<^^int, detail::any_type>(cls);
B::template add_method<std::array<std::meta::info, 1>{^^int},
B::template add_static_method<std::array<std::meta::info, 1>{^^int},
B::template add_operator<std::array<std::meta::info, 1>{^^int}>(cls);
B::template add_enumerator<^^int, detail::any_type>(en);
B::template finish_enum<detail::any_enum>(en);
}
The one bindability fact a backend must provide: can it natively convert a type without welder regist...
The contract a rod (a welder backend, welder::rods::…::rod) must satisfy to plug into the generic dri...
A placeholder class type for shape-probing a member template inside a concept.
The contract a rod (a welder backend, welder::rods::…::rod) must satisfy to plug into the generic driver.
A rod B is a stateless struct; nothing is inherited, and every member is static. The concept shape-checks almost the whole contract — the associated types, the module/session machinery, and every emission hook — so a rod that omits or mis-signs one fails here with a clear "not a `welder::rod`" rather than a deep error the first time the driver instantiates it. The templated hooks can't be quantified over every type/reflection, so — as welder::caster_oracle probes has_native_caster — they are probed once with fixed placeholders (welder::detail::any_type, welder::detail::any_enum, ^^int), checking shape (the hook exists with a compatible signature), not per-type correctness. The per-class / per-enum hooks are probed against the rod's own declared handle types (class_handle_type / enum_handle_type); every emission hook returns void, so only signatures are substituted and no hook body is instantiated.
- Note
- The one gap: the factories themselves. make_class and make_enum return auto, so merely naming them in a requirement would force their bodies to be instantiated to deduce the return type — and a rod's make_class legitimately does real work there (the sol2 rod registers a type's constructors inside it), which a placeholder type does not survive. So the two factories stay contract-by-documentation**, enforced when the driver instantiates the rod over a real welded type. The concept sidesteps them by requiring the handle types as associated aliases* (class_handle_type<T> / enum_handle_type<E> — what the factories yield) rather than deducing them from a factory call, which is what lets the per-handle hooks be checked without instantiating any factory body.
Associated:**
static constexpr lang language;
using module_type = ...;
template <class T> static constexpr bool has_native_caster;
template <class T> using class_handle_type = ...;
template <class E> using enum_handle_type = ...;
lang
The target languages welder ships rods for — but not the whole value space.
Type binding** (the class handle is class_handle_type<T>, what make_class returns). The per-member hooks take a trailing class Style (a welder::naming::name_style) so the rod resolves its own name via welder::name_of<Mem, language, Style, ent_kind::…>() — which also applies any [[=welder::weld_as]] override. The class name is styled by the driver and passed to make_class ready-made.
Callables arrive as whole overload groups — an auto Fns non-type argument, a std::array<std::meta::info, N> (N ≥ 1, declaration order) of overloads that share one target name. The CARRIAGE computes the group from its resolution and gates every member; the rod only emits — a chained-def framework (pybind11) loops the group, a one-value-per-name framework (the Lua rods) registers it as one overload set. The group's name resolves from Fns[0]. Constructors arrive the same way, as one add_constructors call carrying the participating constructor reflections plus the two carriage-computed synthesized forms (the default constructor — decided against construction_type<T> where the rod nominates one — and the aggregate field constructor):
template <class T, auto Bases, std::size_t... I>
static auto make_class(module_type&,
const char* name,
const char*
doc,
std::index_sequence<I...>);
template <class T, auto Bases, std::size_t... I>
static auto make_nested_class(module_type&, auto& outer_cls, const char* name,
const char*
doc, std::index_sequence<I...>);
template <class T, std::meta::info Decl, auto Bases, std::size_t... I>
static auto make_nested_class(module_type&, auto& outer_cls, const char* name,
const char*
doc, std::index_sequence<I...>);
template <class E>
static auto make_nested_enum(module_type&, auto& outer_cls, const char* name,
template <class T>
static void finish_nested_class(module_type&, auto& outer_cls, auto& cls,
const char* name);
template <class T, auto Ctors, bool HasDefault, bool Aggregate>
static void add_constructors(auto& cls);
template <std::meta::info Mem, class Style> static void add_field(auto& cls);
template <auto Fns, class Style> static void add_method(auto& cls);
template <auto Fns, class Style> static void add_static_method(auto& cls);
template <auto Fns> static void add_operator(auto& cls);
static consteval const char* special_method_name(std::meta::info op_fn);
consteval detail::doc_spec< N > doc(const char(&s)[N])
Attach a docstring to a namespace, class, function, or function parameter.
Enum binding** (the enum handle is whatever make_enum returns; deduced):
template <class E> static auto make_enum(module_type&, const char* name,
template <std::meta::info Enum, class Style> static void add_enumerator(auto& e);
template <class E> static void finish_enum(auto& e);
Namespace / module binding** (a "session" is backend scratch state — e.g. an accumulator for deferred, batched attributes — obtained per (sub)module):
static auto open_module(module_type&);
static void set_module_doc(module_type&,
const char*
doc);
template <auto Fns, class Style> static void add_function(module_type&, const char* name = nullptr);
template <std::meta::info Var, class Style> static void add_variable(module_type&, session&, const char* name = nullptr);
static module_type add_submodule(module_type&, const char* name);
static void close_module(module_type&, session&);
- Template Parameters
-
Definition at line 206 of file concepts.hpp.