Group scl_utility_preprocessor
Modules > scl_utility_preprocessor
Helper macros for the C/C++ preprocessor. More...
Files
| Type | Name |
|---|---|
| file | counter.h Implements a compile-time counter mechanism. |
| file | forward.h Provides a utility macro for forcing the expansion of other macros. |
Macros
| Type | Name |
|---|---|
| define | SCL_COUNTER_NEXT (Tag) /* multi line expression */Increments a compile-time counter. |
| define | SCL_COUNTER_VALUE (Tag) Reads the current value of a compile-time counter. |
| define | SCL_FORWARD (...) \_\_VA\_ARGS\_\_Identity macro that forwards variadic arguments unchanged and can force expansion of nested macros. |
Detailed Description
- Utilities for macro expansion and safe forwarding of tokens.
- Building blocks for more complex preprocessor metaprogramming patterns.
- Designed to be portable and minimal.
Macro Definition Documentation
define SCL_COUNTER_NEXT
Increments a compile-time counter.
#define SCL_COUNTER_NEXT (
Tag
) `/* multi line expression */`
This macro defines a new crumb function overload in the scl namespace. This new function is a better match for overload resolution for a specific bit-rank, effectively "setting" that bit and incrementing the counter's value for subsequent reads via SCL_COUNTER_VALUE.
Parameters:
TagThe unique identifier for the counter to increment. Can be a template type.
struct MyCounterTag1 {};
// The counter starts at 0 before any increments
constexpr auto val1_0 = SCL_COUNTER_VALUE(MyCounterTag1);
static_assert(val1_0, 0);
SCL_COUNTER_NEXT(MyCounterTag1)
constexpr auto val1_1 = SCL_COUNTER_VALUE(MyCounterTag1);
static_assert(val1_1, 1);
SCL_COUNTER_NEXT(MyCounterTag1)
constexpr auto val1_2 = SCL_COUNTER_VALUE(MyCounterTag1);
static_assert(val1_2, 2);
define SCL_COUNTER_VALUE
Reads the current value of a compile-time counter.
#define SCL_COUNTER_VALUE (
Tag
)
This macro constructs the counter's value by checking for crumb overloads for each bit from 0 to 31. It chains SCL_COUNTER_CRUMB calls, where each call resolves to the most specific crumb function available for its rank.
Parameters:
TagThe unique identifier for the counter. Can be a template type.
Returns:
A constexpr value of type std::uint_fast32_t.
template <typename T>
struct TemplateTag {};
// The SCL_FORWARD macro is crucial here
constexpr auto tpl_val_0 = SCL_COUNTER_VALUE(TemplateTag<int>);
static_assert(tpl_val_0 == 0);
SCL_COUNTER_NEXT(TemplateTag<int>)
constexpr auto tpl_val_1 = SCL_COUNTER_VALUE(TemplateTag<int>);
static_assert(tpl_val_1 == 1);
// A different specialization of the same template tag should be a different counter
constexpr auto tpl_val_float_0 = SCL_COUNTER_VALUE(TemplateTag<float>);
static_assert(tpl_val_float_0 == 0);
define SCL_FORWARD
Identity macro that forwards variadic arguments unchanged and can force expansion of nested macros.
#define SCL_FORWARD (
...
) `__VA_ARGS__`
This macro simply expands to its variadic arguments. It is useful when: * You need to forward comma-separated tokens as-is into another macro, function call, or template parameter list. * You want to force expansion in macro chaining scenarios where another macro yields comma-separated tokens.
Parameters:
...Variadic tokens to forward unchanged.
Note:
- This macro does not add parentheses or alter tokenization; it only forwards tokens.
- It is safe to use in both C and C++ code. In C++ contexts, it is commonly used with template parameter packs and function calls.
// Example 1: Forwarding arguments to a function call
#define CALL(fn, ...) fn(__VA_ARGS__)
int add(int a, int b) { return a + b; }
int result = CALL(add, SCL_FORWARD(1, 2)); // expands to add(1, 2)
// Example 2: Forcing expansion for template parameter lists
#define BASIC_TYPES int, long, double
template <typename... Ts>
struct type_list {};
using tl = type_list<SCL_FORWARD(BASIC_TYPES)>; // expands to type_list<int, long, double>
// Example 3: Chaining macros that produce comma-separated tokens
#define MAKE_PAIR(a, b) a, b
auto p = std::pair<SCL_FORWARD(MAKE_PAIR(int, double))>{1, 2.0};
// Example 4: Forwarding arguments through another macro layer
#define FORWARD_TO_EMPLACE(obj, ...) obj.emplace_back(__VA_ARGS__)
std::vector<std::pair<int, std::string>> v;
FORWARD_TO_EMPLACE(v, SCL_FORWARD(42, "answer")); // emplace_back(42, "answer")
Warning:
- Be mindful of operator precedence; if you need grouping, use parentheses in the call sites.
- Since macros are global, avoid generic names to reduce collision risk (SCL_ prefix is used for this reason).