alexandrescu-modern-cpp-design
Andrei Alexandrescu Style Guide
Overview
Andrei Alexandrescu's "Modern C++ Design" revolutionized how we think about C++ templates. His work on Loki library and policy-based design showed that templates are not just for containers—they're a compile-time programming language.
Core Philosophy
"C++ templates are Turing-complete. Use this power wisely."
"Policy-based design: assemble types from interchangeable parts."
Alexandrescu believes in pushing computation to compile time and using the type system as a design tool, not just a safety mechanism.
Design Principles
-
Policy-Based Design: Build classes from interchangeable policy classes that customize behavior without inheritance overhead.
-
Compile-Time over Runtime: What can be computed at compile time should be.
-
Type Lists and Metaprogramming: Types themselves become first-class citizens that can be manipulated.
-
Design Patterns in Types: Classic GoF patterns implemented with zero runtime overhead.
When Writing Code
Always
- Consider if behavior can be a compile-time policy
- Use
static_assertto document and enforce requirements - Prefer tag dispatching over runtime branching for type-based logic
- Make templates SFINAE-friendly (C++11/14) or use concepts (C++20)
- Document template requirements explicitly
Never
- Use runtime polymorphism when static polymorphism suffices
- Write duplicate code that differs only in types
- Ignore compile-time computation opportunities
- Leave template errors to become cryptic instantiation failures
Prefer
- Policy classes over strategy pattern (no vtable)
- Type traits over runtime type checking
constexprfunctions over template metafunctions (modern C++)- Concepts over SFINAE (C++20)
- Variadic templates over recursive type lists (modern C++)
Code Patterns
Policy-Based Design
// Traditional OOP: Runtime overhead, fixed at compile time anyway
class Widget : public ICreationPolicy, public IThreadingPolicy { /* ... */ };
// Policy-Based: Zero overhead, infinitely configurable
template <
class CreationPolicy,
class ThreadingPolicy = SingleThreaded,
class CheckingPolicy = NoChecking
>
class SmartPtr : public CreationPolicy,
public ThreadingPolicy,
public CheckingPolicy {
// Policies are mixed in, no vtable
};
// Usage: Configure at compile time
using ThreadSafePtr = SmartPtr<HeapCreation, MultiThreaded, AssertCheck>;
using FastPtr = SmartPtr<HeapCreation, SingleThreaded, NoChecking>;
// Policies are just classes with required interface
struct HeapCreation {
template<class T>
static T* Create() { return new T; }
template<class T>
static void Destroy(T* p) { delete p; }
};
struct SingleThreaded {
struct Lock {
Lock() = default; // No-op
};
};
struct MultiThreaded {
struct Lock {
Lock() { /* acquire mutex */ }
~Lock() { /* release mutex */ }
};
};
Type Traits and SFINAE
// Type trait: Does T have a serialize() method?
template<typename T, typename = void>
struct has_serialize : std::false_type {};
template<typename T>
struct has_serialize<T,
std::void_t<decltype(std::declval<T>().serialize())>
> : std::true_type {};
// Use it for conditional behavior
template<typename T>
auto save(const T& obj) -> std::enable_if_t<has_serialize<T>::value> {
obj.serialize();
}
template<typename T>
auto save(const T& obj) -> std::enable_if_t<!has_serialize<T>::value> {
default_serialize(obj);
}
// C++20: Much cleaner with concepts
template<typename T>
concept Serializable = requires(T t) {
{ t.serialize() } -> std::convertible_to<std::string>;
};
void save(Serializable auto const& obj) {
obj.serialize();
}
Compile-Time Type Lists (Classic Alexandrescu)
// Type list: A compile-time list of types
template<typename... Ts>
struct TypeList {};
// Operations on type lists
template<typename List>
struct Length;
template<typename... Ts>
struct Length<TypeList<Ts...>> {
static constexpr size_t value = sizeof...(Ts);
};
// Get type at index
template<size_t I, typename List>
struct TypeAt;
template<typename Head, typename... Tail>
struct TypeAt<0, TypeList<Head, Tail...>> {
using type = Head;
};
template<size_t I, typename Head, typename... Tail>
struct TypeAt<I, TypeList<Head, Tail...>> {
using type = typename TypeAt<I - 1, TypeList<Tail...>>::type;
};
// Usage
using MyTypes = TypeList<int, double, std::string>;
static_assert(Length<MyTypes>::value == 3);
using Second = TypeAt<1, MyTypes>::type; // double
Visitor Pattern via Templates
// Traditional visitor: Virtual dispatch at every node
// Alexandrescu approach: Static visitor with type list
template<typename... Types>
class Variant;
template<typename Visitor, typename Variant>
auto visit(Visitor&& v, Variant&& var) {
return var.visit(std::forward<Visitor>(v));
}
// Modern C++ (std::variant does this)
using Value = std::variant<int, double, std::string>;
auto result = std::visit(overloaded{
[](int i) { return std::to_string(i); },
[](double d) { return std::to_string(d); },
[](const std::string& s) { return s; }
}, value);
// The 'overloaded' helper (Alexandrescu-style)
template<class... Ts>
struct overloaded : Ts... {
using Ts::operator()...;
};
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
Mental Model
Alexandrescu thinks of C++ templates as a compile-time functional language:
- Types as values: Types can be computed, stored, and transformed
- Templates as functions: Template instantiation is function application
- Specialization as pattern matching: Like case statements on types
- Recursion for iteration: Compile-time loops via recursive templates
The D Language Connection
Alexandrescu later co-designed D, which incorporates many C++ template lessons:
- Built-in compile-time function execution
- String mixins for code generation
- Better error messages for templates
These ideas now appear in modern C++ (constexpr, if constexpr, concepts).
When to Apply
Use Alexandrescu's techniques when:
- You need maximum performance (zero runtime overhead)
- Behavior variations are known at compile time
- You're building a library with many configuration options
- Type-based dispatch is frequent
Avoid when:
- Runtime polymorphism is genuinely needed
- Compile times are already problematic
- Team isn't comfortable with template metaprogramming
More from copyleftdev/sk1llz
google-material-design
Design interfaces following Google's Material Design system, the unified visual language bridging digital and physical worlds. Emphasizes bold graphic design, intentional motion, adaptive layouts, and the material metaphor. Use when building modern, accessible, delightful user interfaces across platforms.
119renaissance-statistical-arbitrage
Build trading systems in the style of Renaissance Technologies, the most successful quantitative hedge fund in history. Emphasizes statistical arbitrage, signal processing, and rigorous scientific methodology. Use when developing alpha research, signal extraction, or systematic trading strategies.
104aqr-factor-investing
Build investment systems in the style of AQR Capital Management, the quantitative investment firm pioneering factor investing. Emphasizes academic rigor, transparent methodology, and systematic factor exposure. Use when building factor models, conducting asset pricing research, or designing systematic portfolios.
103minervini-swing-trading
Trade swing setups in the style of Mark Minervini, 3x US Investing Champion with 220%+ annual returns. Emphasizes SEPA methodology, trend templates, volatility contraction patterns (VCP), and strict risk management. Use when swing trading momentum stocks, identifying breakout setups, or building systematic trend-following strategies.
84de-shaw-computational-finance
Build trading systems in the style of D.E. Shaw, the pioneering computational finance firm. Emphasizes systematic strategies, rigorous quantitative research, and world-class technology infrastructure. Use when building research platforms, systematic trading strategies, or quantitative finance infrastructure.
63jump-trading-fpga-hft
Build trading systems in the style of Jump Trading, the high-frequency trading firm pioneering FPGA-based trading. Emphasizes hardware acceleration, network optimization, and nanosecond-level execution. Use when building FPGA trading systems, network-optimized infrastructure, or ultra-low-latency order execution.
29