"ScL Feature"/
SCL Feature 0.0.1
C++20 composable proxy wrapper with pluggable executor strategy
Loading...
Searching...
No Matches
method.h File Reference

Compile-time method reflection macros for wrapper types. More...

Go to the source code of this file.

Macros

#define SCL_REFLECT_METHOD(method)
 Generates proxy methods that reflect method from the wrapped object through the executor, for all 8 cv-ref qualifier combinations.

Detailed Description

Compile-time method reflection macros for wrapper types.

Provides macros to automatically generate proxy methods that forward calls from a wrapper class to the held object through an executor, preserving cv-ref qualifiers exactly.

The executor is located at runtime via scl::feature::executor_trait, which must be specialized for each wrapper type.

Requirements on the enclosing class
  1. Declare the wrapper type with SCL_REFLECT_TYPE(Type,Member) (after the executor member declaration).
  2. Specialize scl::feature::executor_trait for the wrapper type.
  3. The executor type must provide a static value(exec) method that returns a reference to the wrapped object.
Example
struct MyWrapper;
template <>
struct scl::feature::executor_trait<MyWrapper> {
template <typename Self>
static constexpr decltype(auto) executor(Self && self)
{ return ::scl::forward_like<Self>(self.m_exec); }
};
struct MyWrapper {
Executor m_exec;
SCL_REFLECT_TYPE(MyWrapper, m_exec);
};
#define SCL_REFLECT_METHOD(method)
Generates proxy methods that reflect method from the wrapped object through the executor,...
Definition method.h:223
Trait that provides access to the executor inside a wrapper.
Definition executor.h:33
#define SCL_REFLECT_TYPE(Type, Member)
Declares the wrapper type for use by SCL_REFLECT_METHOD.
Definition type.h:27

Macro Definition Documentation

◆ SCL_REFLECT_METHOD

#define SCL_REFLECT_METHOD ( method)

Generates proxy methods that reflect method from the wrapped object through the executor, for all 8 cv-ref qualifier combinations.

For each of the 8 cv-ref qualifiers (&, &&, const&, const&&, volatile&, volatile&&, const volatile&, const volatile&&) two overloads are generated:

  • one with deduced template arguments — template<typename... A_r_g_s__>
  • one with explicit template arguments — template<typename\ P_a_r_a_m__,\ typename... P_a_r_a_m_s__,\ typename... A_r_g_s__>

This gives 16 overloads in total (2 × 8).

Executor access
The executor is obtained at runtime via scl::feature::executor_trait<WrapperType>::executor(self). The default trait returns self.m_executor. Specialize the trait for types that store the executor differently.

The wrapped value is then obtained by calling Executor::value(executor_ref).

Constraint — callability
Each overload is constrained by two requires clauses:
  1. The wrapped object's method must be callable with the given arguments for the particular cv-ref qualification.
  2. SCL_HAS_QUALIFIED_METHOD must confirm that the wrapped object has a dedicated overload for that qualifier (not an implicit cv-widening fallback). This prevents, for example, a const& proxy from being generated when only a mutable & overload exists on the target.
Constraint — different return types required
Because SCL_HAS_QUALIFIED_METHOD relies on return-type discrimination, overloads of the target method with different cv-ref qualifiers must return different types. If two overloads return the same type, the macro will produce a false negative.
struct Good {
short get() &; // short ≠ int → distinguishable
int get() const &;
};
struct Bad {
int get() &; // int == int → macro cannot distinguish
int get() const &;
};
Template methods
If method is a template on the wrapped object (e.g. template<typename\ T>\ T\ convert()), users can call the reflected method with explicit template arguments: wrapper.convert<double>().

Internally this is handled by a helper struct (METHOD_S_c_L_caller_) generated inside the enclosing class. The struct wraps the .template method<...> call inside a static function template whose object parameter (O_b_j___) is dependent. This ensures that the template keyword appears only in a dependent context, so the compiler defers name lookup to instantiation time. Without this indirection, .template foo<...> on a non-dependent type where foo is not a template would be a hard parse error (not SFINAE), even inside a requires expression.

When method is not a template, the helper struct's call function fails to instantiate (SFINAE via trailing return type), the requires clause evaluates to false, and the explicit-template-args overload is silently discarded.

Example
struct Target {
short get() &;
int get() const &;
float get() &&;
template <typename T>
T convert() const &;
};
struct MyWrapper;
template <>
struct scl::feature::executor_trait<MyWrapper> {
template <typename Self>
static constexpr decltype(auto) executor(Self && self)
{ return ::scl::forward_like<Self>(self.m_executor); }
};
struct MyWrapper {
::scl::feature::inplace::plain<Target> m_executor;
SCL_REFLECT_TYPE(MyWrapper, m_executor);
explicit MyWrapper(int v) : m_executor{v} {}
SCL_REFLECT_METHOD(get) // 16 overloads, constrained to &, const&, &&
SCL_REFLECT_METHOD(convert) // 16 overloads, only const& survives constraints
};
MyWrapper w{42};
w.get(); // calls Target::get() & → short(42)
MyWrapper const cw{42};
cw.get(); // calls Target::get() const & → int(92)
MyWrapper{42}.get(); // calls Target::get() && → float(142)
cw.convert<double>(); // calls Target::convert<double>() const & → 42.0
Root namespace of the ScL project.
Parameters
methodUnqualified method name (plain identifier).
See also
SCL_REFLECT_TYPE
scl::feature::executor_trait