
C++ token pasting metaprogramming provides intermediate developers with a low-friction way to generate near-identical classes without wrestling with heavyweight template tricks.
By combining the pre‑processor’s ## operator with non‑type template parameters (NTTPs), you can programmatically splice together function names on the fly, feed them straight into a templated wrapper, and keep your codebase DRY, even when library naming conventions aren’t friendly to templates.
This example demonstrates a compact metaprogramming pattern that glues together three C++ tools:
- The pre‑processor – builds identifiers by token‑pasting.
- Non‑Type Template Parameters (NTTP) – passes function pointers as template arguments.
- A thin forwarding class template – exposes the function behind the pointer.
//==================================================================================================
// Example: Generating Closely‑Related Classes with the Pre‑Processor and NTTPs //
//==================================================================================================
//---------------------------------------------
// 1. Required headers
//---------------------------------------------
#include <iostream>
//---------------------------------------------
// 2. Pre‑processor utilities
//---------------------------------------------
//
// CONCAT() concatenates two tokens **at compile time**.
// `A ## B` literally glues A and B together before the compiler ever sees them.
// There is *no* runtime cost.
//
#define CONCAT(A, B) A ## B
//---------------------------------------------
// 3. Library code we cannot change
//---------------------------------------------
//
// Imagine these free functions live inside a vendor library.
// Their names follow the pattern <Category>FunctionOne().
//
int FooFunctionOne()
{
return 1;
}
int BarFunctionOne()
{
return -1;
}
//---------------------------------------------
// 4. Generic wrapper driven by an NTTP
//---------------------------------------------
//
// ‑ `Func` is a **non‑type template parameter** holding a *function pointer*.
// ‑ At instantiation the compiler substitutes the pointer’s *value*, so calls are
// resolved at compile time and inlined in practice.
//
template<int (*Func)()>
class UsesTemplates
{
public:
int CallFunction()
{
return Func(); // always use braces
}
};
//---------------------------------------------
// 5. Convenience macro for class instantiation
//---------------------------------------------
//
// ‑ The caller supplies a *category prefix* (Foo / Bar / …).
// ‑ CONCAT builds the required symbol name <Prefix>FunctionOne.
// ‑ The resulting token is fed to the template as a pointer.
//
// Example: TEMPLATE_CLASS(Foo) -> UsesTemplates<&FooFunctionOne>
//
#define TEMPLATE_CLASS(PREFIX) UsesTemplates<&CONCAT(PREFIX, FunctionOne)>
//---------------------------------------------
// 6. Demonstration
//---------------------------------------------
int main()
{
TEMPLATE_CLASS(Foo) fooClass; // Expands to UsesTemplates<&FooFunctionOne>
TEMPLATE_CLASS(Bar) barClass; // Expands to UsesTemplates<&BarFunctionOne>
const auto fooValue { fooClass.CallFunction() };
const auto barValue { barClass.CallFunction() };
std::cout << "Foo = " << fooValue << '\n';
std::cout << "Bar = " << barValue << '\n';
return 0;
}When compiled, we can see the string substitution was successful:
UsesTemplates<&FooFunctionOne()>::CallFunction():
push rbp
mov rbp, rsp
sub rsp, 8
mov QWORD PTR [rbp-8], rdi
call FooFunctionOne()
leave
ret
Token Pasting Metaprogramming: Key Take‑aways
This example demonstrates three key points about C++ template metaprogramming, specifically using NTTPs:
- Token pasting (##) lets you compute identifiers using simple placeholders.
- Mixing token pasting with NTTPs cleanly bridges “pre‑processor world” and “template world”.
- The technique scales: add BazFunctionOne(), then use TEMPLATE_CLASS(Baz) – no new code.
C++ token pasting metaprogramming may seem like a niche technique, but it neatly bridges the gap between rigid third-party naming schemes and the type-safe elegance of modern templates. Master it once, and you can roll out families of boilerplate-free wrappers, reduce maintenance overhead, and keep your abstractions clean – precisely the kind of pragmatic win for solid C++ craftsmanship.
Want more C++ tips? Check out these posts:
- C++ Performance Checklist for Low-Latency Systems
- C++ Error Handling Strategies – Benchmarks and Performance
- The Definitive Guide to the C++ final Keyword
- The Humble and Surprising C++ Semicolon; Origins, Use, and Art
Discover more from John Farrier
Subscribe to get the latest posts sent to your email.