Claude-skill-registry alexandrescu-modern-cpp-design
Write C++ code following Andrei Alexandrescu's Modern C++ Design principles. Emphasizes policy-based design, template metaprogramming, and type-safe generic abstractions. Use when designing flexible, reusable libraries or when compile-time computation beats runtime overhead.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/alexandrescu" ~/.claude/skills/majiayu000-claude-skill-registry-alexandrescu-modern-cpp-design && rm -rf "$T"
skills/data/alexandrescu/SKILL.mdAndrei 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
to document and enforce requirementsstatic_assert - 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
functions over template metafunctions (modern C++)constexpr- 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