$npx -y skills add affaan-m/ECC --skill cpp-coding-standardsC++ coding standards based on the C++ Core Guidelines (isocpp.github.io). Use when writing, reviewing, or refactoring C++ code to enforce modern, safe, and idiomatic practices.
| 1 | # C++ Coding Standards (C++ Core Guidelines) |
| 2 | |
| 3 | Comprehensive coding standards for modern C++ (C++17/20/23) derived from the [C++ Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines). Enforces type safety, resource safety, immutability, and clarity. |
| 4 | |
| 5 | ## When to Use |
| 6 | |
| 7 | - Writing new C++ code (classes, functions, templates) |
| 8 | - Reviewing or refactoring existing C++ code |
| 9 | - Making architectural decisions in C++ projects |
| 10 | - Enforcing consistent style across a C++ codebase |
| 11 | - Choosing between language features (e.g., `enum` vs `enum class`, raw pointer vs smart pointer) |
| 12 | |
| 13 | ### When NOT to Use |
| 14 | |
| 15 | - Non-C++ projects |
| 16 | - Legacy C codebases that cannot adopt modern C++ features |
| 17 | - Embedded/bare-metal contexts where specific guidelines conflict with hardware constraints (adapt selectively) |
| 18 | |
| 19 | ## Cross-Cutting Principles |
| 20 | |
| 21 | These themes recur across the entire guidelines and form the foundation: |
| 22 | |
| 23 | 1. **RAII everywhere** (P.8, R.1, E.6, CP.20): Bind resource lifetime to object lifetime |
| 24 | 2. **Immutability by default** (P.10, Con.1-5, ES.25): Start with `const`/`constexpr`; mutability is the exception |
| 25 | 3. **Type safety** (P.4, I.4, ES.46-49, Enum.3): Use the type system to prevent errors at compile time |
| 26 | 4. **Express intent** (P.3, F.1, NL.1-2, T.10): Names, types, and concepts should communicate purpose |
| 27 | 5. **Minimize complexity** (F.2-3, ES.5, Per.4-5): Simple code is correct code |
| 28 | 6. **Value semantics over pointer semantics** (C.10, R.3-5, F.20, CP.31): Prefer returning by value and scoped objects |
| 29 | |
| 30 | ## Philosophy & Interfaces (P.*, I.*) |
| 31 | |
| 32 | ### Key Rules |
| 33 | |
| 34 | | Rule | Summary | |
| 35 | |------|---------| |
| 36 | | **P.1** | Express ideas directly in code | |
| 37 | | **P.3** | Express intent | |
| 38 | | **P.4** | Ideally, a program should be statically type safe | |
| 39 | | **P.5** | Prefer compile-time checking to run-time checking | |
| 40 | | **P.8** | Don't leak any resources | |
| 41 | | **P.10** | Prefer immutable data to mutable data | |
| 42 | | **I.1** | Make interfaces explicit | |
| 43 | | **I.2** | Avoid non-const global variables | |
| 44 | | **I.4** | Make interfaces precisely and strongly typed | |
| 45 | | **I.11** | Never transfer ownership by a raw pointer or reference | |
| 46 | | **I.23** | Keep the number of function arguments low | |
| 47 | |
| 48 | ### DO |
| 49 | |
| 50 | ```cpp |
| 51 | // P.10 + I.4: Immutable, strongly typed interface |
| 52 | struct Temperature { |
| 53 | double kelvin; |
| 54 | }; |
| 55 | |
| 56 | Temperature boil(const Temperature& water); |
| 57 | ``` |
| 58 | |
| 59 | ### DON'T |
| 60 | |
| 61 | ```cpp |
| 62 | // Weak interface: unclear ownership, unclear units |
| 63 | double boil(double* temp); |
| 64 | |
| 65 | // Non-const global variable |
| 66 | int g_counter = 0; // I.2 violation |
| 67 | ``` |
| 68 | |
| 69 | ## Functions (F.*) |
| 70 | |
| 71 | ### Key Rules |
| 72 | |
| 73 | | Rule | Summary | |
| 74 | |------|---------| |
| 75 | | **F.1** | Package meaningful operations as carefully named functions | |
| 76 | | **F.2** | A function should perform a single logical operation | |
| 77 | | **F.3** | Keep functions short and simple | |
| 78 | | **F.4** | If a function might be evaluated at compile time, declare it `constexpr` | |
| 79 | | **F.6** | If your function must not throw, declare it `noexcept` | |
| 80 | | **F.8** | Prefer pure functions | |
| 81 | | **F.16** | For "in" parameters, pass cheaply-copied types by value and others by `const&` | |
| 82 | | **F.20** | For "out" values, prefer return values to output parameters | |
| 83 | | **F.21** | To return multiple "out" values, prefer returning a struct | |
| 84 | | **F.43** | Never return a pointer or reference to a local object | |
| 85 | |
| 86 | ### Parameter Passing |
| 87 | |
| 88 | ```cpp |
| 89 | // F.16: Cheap types by value, others by const& |
| 90 | void print(int x); // cheap: by value |
| 91 | void analyze(const std::string& data); // expensive: by const& |
| 92 | void transform(std::string s); // sink: by value (will move) |
| 93 | |
| 94 | // F.20 + F.21: Return values, not output parameters |
| 95 | struct ParseResult { |
| 96 | std::string token; |
| 97 | int position; |
| 98 | }; |
| 99 | |
| 100 | ParseResult parse(std::string_view input); // GOOD: return struct |
| 101 | |
| 102 | // BAD: output parameters |
| 103 | void parse(std::string_view input, |
| 104 | std::string& token, int& pos); // avoid this |
| 105 | ``` |
| 106 | |
| 107 | ### Pure Functions and constexpr |
| 108 | |
| 109 | ```cpp |
| 110 | // F.4 + F.8: Pure, constexpr where possible |
| 111 | constexpr int factorial(int n) noexcept { |
| 112 | return (n <= 1) ? 1 : n * factorial(n - 1); |
| 113 | } |
| 114 | |
| 115 | static_assert(factorial(5) == 120); |
| 116 | ``` |
| 117 | |
| 118 | ### Anti-Patterns |
| 119 | |
| 120 | - Returning `T&&` from functions (F.45) |
| 121 | - Using `va_arg` / C-style variadics (F.55) |
| 122 | - Capturing by reference in lambdas passed to other threads (F.53) |
| 123 | - Returning `const T` which inhibits move semantics (F.49) |
| 124 | |
| 125 | ## Classes & Class Hierarchies (C.*) |
| 126 | |
| 127 | ### Key Rules |
| 128 | |
| 129 | | Rule | Summary | |
| 130 | |------|---------| |
| 131 | | **C.2** | Use `class` if invariant exists; `struct` if data members vary independently | |
| 132 | | **C.9** | Minimize exposure of members | |
| 133 | | **C.20** | If you can avoid defining default operations, do (Rule of Zero) | |
| 134 | | **C.21** | If you define or `=delete` any copy/move/destructor, handle them all (Rule of Five) | |
| 135 | | **C.35** | Base class destructor: public vi |