diff options
| author | Leitwolf11 | 2026-10-31 13:01:04 +0300 |
|---|---|---|
| committer | Leitwolf11 | 2026-10-31 13:01:04 +0300 |
| commit | 1f5458322669301f62599c1ec5dacb77b5dc2d8d (patch) | |
| tree | 7e32402fa9c06014328a27d7972c2fb1a9484352 | |
| parent | 8d1fb4807edc7920fbecd0554c9c61625827e19c (diff) | |
| download | progmasoft-cpp-1f5458322669301f62599c1ec5dacb77b5dc2d8d.tar.gz | |
Cover C++17 as well as C++20docs/cpp17-and-cpp20
A project now picks one version. C++20 stays the default, and C++17 is
for libraries meant for other people's projects, because it is still the
widest common target and works in every later standard.
Section 5.13 gives the C++17 form of each C++20 feature the guide uses
and the checks such a project needs: CI in the versions it promises, with
each compiler, and headers that compile in default compiler modes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rw-r--r-- | ADOPTING.md | 2 | ||||
| -rw-r--r-- | CHANGELOG.md | 4 | ||||
| -rw-r--r-- | Guide/C-INTERFACES.md | 4 | ||||
| -rw-r--r-- | Guide/ERRORS.md | 2 | ||||
| -rw-r--r-- | Guide/FORMATTING.md | 2 | ||||
| -rw-r--r-- | Guide/LANGUAGE.md | 44 | ||||
| -rw-r--r-- | Guide/TOOLING.md | 4 | ||||
| -rw-r--r-- | Guide/TYPES-AND-CLASSES.md | 2 | ||||
| -rw-r--r-- | README.md | 6 |
9 files changed, 58 insertions, 12 deletions
diff --git a/ADOPTING.md b/ADOPTING.md index 2fc3f12..370f181 100644 --- a/ADOPTING.md +++ b/ADOPTING.md @@ -21,6 +21,8 @@ Deviations of this project are listed below. Do not copy the rules into the project. A copy drifts from the guide, and two documents that disagree are worse than one. +State the language version in the same section, C++20 or C++17; [the guide says how to choose](Guide/LANGUAGE.md). + ## 2. Copy the profiles | File | From | diff --git a/CHANGELOG.md b/CHANGELOG.md index feefc35..43b58b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ A revision of the guide is named by its date. A change that requires existing co ## Unreleased +The guide covers C++17 as well as C++20. A project picks one; C++20 stays the default, and C++17 is for libraries meant +for other people's projects. [Section 5.13](Guide/LANGUAGE.md#513-c17-projects) lists the C++17 form of each C++20 +feature the guide uses. Existing C++20 projects need no change. + ## 2026-10-18 The first revision of Progmasoft C++ Style. It writes down the conventions of the Progmasoft C++ projects and decides diff --git a/Guide/C-INTERFACES.md b/Guide/C-INTERFACES.md index 3fc7b60..2def35e 100644 --- a/Guide/C-INTERFACES.md +++ b/Guide/C-INTERFACES.md @@ -4,7 +4,7 @@ # 10. C interfaces A C interface is the stable binary boundary of a library: what another language, another compiler or another version of -the library links against. It is written in C11 and kept small; everything behind it is C++20. +the library links against. It is written in C11 and kept small; everything behind it is C++. ## 10.1 The header @@ -83,7 +83,7 @@ example_parser_destroy(example_parser *parser); ## 10.4 The C++ side -Behind the interface, the implementation is ordinary C++20 that follows the rest of this guide: +Behind the interface, the implementation is ordinary C++ that follows the rest of this guide: ```cpp extern "C" auto diff --git a/Guide/ERRORS.md b/Guide/ERRORS.md index e57c790..20c524f 100644 --- a/Guide/ERRORS.md +++ b/Guide/ERRORS.md @@ -27,7 +27,7 @@ never lets one cross a C interface or escape a destructor. Third-party code keep ## 7.2 `Expected<T>` and `Error` A function that produces a value or fails returns `Expected<T>`; one that only succeeds or fails returns `Error`. The guide -does not prescribe the library. `llvm::Expected<T>` and `llvm::Error` suit code that already depends on LLVM; a C++20 +does not prescribe the library. `llvm::Expected<T>` and `llvm::Error` suit code that already depends on LLVM; a backport of `std::expected` (such as `tl::expected`) or a small type of the project's own suit the rest, and C++23's `std::expected` replaces them once a project moves to it. What matters is the discipline below: the failure is in the signature, it cannot be ignored, and it carries a message. diff --git a/Guide/FORMATTING.md b/Guide/FORMATTING.md index 80a355c..239ee9f 100644 --- a/Guide/FORMATTING.md +++ b/Guide/FORMATTING.md @@ -62,7 +62,7 @@ CI, because two versions can format the same file differently. --- Language: Cpp BasedOnStyle: LLVM -Standard: c++20 +Standard: c++20 # c++17 in a C++17 project UseTab: Never IndentWidth: 4 diff --git a/Guide/LANGUAGE.md b/Guide/LANGUAGE.md index 7163472..7858103 100644 --- a/Guide/LANGUAGE.md +++ b/Guide/LANGUAGE.md @@ -3,8 +3,16 @@ # 5. Language -The guide targets C++20 exactly: `-std=c++20`, no compiler extensions (`-Wpedantic` is on). A C++23 feature is used only -through a library that provides it for C++20, such as `llvm::Expected` in place of `std::expected`. +The guide covers two language versions, and a project picks one: + +- **C++20** is the default, for applications and for libraries used inside one product. +- **C++17** is for a library meant for other people's projects, because C++17 is still the widest common target and code + written for it also works in every later standard. A C++20 library would leave those users out. + +A project builds with exactly its version, `-std=c++20` or `-std=c++17`, and no compiler extensions (`-Wpedantic` is on). +Its deviations do not change the version: a C++17 project uses no C++20 feature, even where a compiler accepts one. +A feature of a later standard is used only through a library that provides it, such as `llvm::Expected` in place of +`std::expected`. [Section 5.13](#513-c17-projects) gives the C++17 form of what the other sections write in C++20. ## 5.1 Functions @@ -168,3 +176,35 @@ validates it. | Non-`const` global and static variables | state passed explicitly, owned by an object with a clear lifetime | | `alloca`, `setjmp`/`longjmp` | ordinary allocation and returns | | User-defined literals | named functions or constructors, except the standard ones such as `std::chrono` suffixes | + +## 5.13 C++17 projects + +The rest of this guide applies unchanged. Where a section uses a C++20 feature, a C++17 project writes this instead: + +| C++20 | C++17 | +| --- | --- | +| Concepts and `requires` | a named trait, `kIsInteger<Type>`, used by `std::enable_if_t` in a defaulted template parameter; `static_assert` when no overload depends on it | +| `operator==` and `operator<=>` `= default` | written out over `std::tie` of all fields, with a test that fails when a field is left out | +| Designated initializers | default construct, then assign the fields; a factory function when this repeats | +| `std::span` | `const std::vector<T> &`, or a view such as `llvm::ArrayRef` where the project has one | +| `std::ranges` | the iterator algorithms: `std::sort(items.begin(), items.end())` | +| `std::bit_cast` | `static_cast` between integers, `std::memcpy` into a value otherwise | +| `consteval`, `constinit` | `constexpr` | +| Template lambdas | a function template in a `Detail` namespace | +| `std::erase_if` | erase-remove: `items.erase(std::remove_if(...), items.end())` | +| `contains`, `starts_with`, `ends_with` | `find`, `compare` or `substr` | +| `std::remove_cvref_t`, `std::identity` | one small header of the project, with a comment naming what it stands for | +| `std::format` | `fmt`, or streaming | +| `std::jthread` | `std::thread`, joined explicitly | +| `using enum` | qualified enumerators | +| `[[likely]]`, `[[unlikely]]` | nothing | + +Code written for C++17 is promised to later standards too, so its checks have to reach them: + +- **CI builds and tests in C++17 and in the newest standard the project supports.** A rule of C++20 can reject C++17 code, + such as the rewritten comparison operators. +- **CI builds with each compiler the project supports, not only Clang.** Clang accepts designated initializers in C++17 + and warns; MSVC rejects them. Clang's `-Wc++20-extensions` shows most of these before CI does. +- **Headers compile under the default modes of the compilers.** MSVC is permissive in C++17 unless `/permissive-` is + given, and a user of the library may not give it. A non-capturing lambda that reads a local `constexpr`, for instance, + is an error there. diff --git a/Guide/TOOLING.md b/Guide/TOOLING.md index 1a2ceaa..5852cd4 100644 --- a/Guide/TOOLING.md +++ b/Guide/TOOLING.md @@ -15,7 +15,7 @@ as errors, in a CI job of its own. ### Flags ```text --std=c++20 +-std=c++20 # -std=c++17 in a C++17 project -fno-exceptions -Wall -Wextra -Wpedantic -Werror -Wshadow @@ -36,7 +36,7 @@ as errors, in a CI job of its own. -Wcomma ``` -With `clang-cl`, each flag is passed as `/clang:<flag>`, and the language standard as `/std:c++20`. +With `clang-cl`, each flag is passed as `/clang:<flag>`, and the language standard as `/std:c++20` or `/std:c++17`. These flags apply to first-party code only. Third-party code is compiled with its own options; its headers are included as system headers (`-isystem`, or the build tool's equivalent), so their warnings do not fail the build. diff --git a/Guide/TYPES-AND-CLASSES.md b/Guide/TYPES-AND-CLASSES.md index d1140a7..93bf064 100644 --- a/Guide/TYPES-AND-CLASSES.md +++ b/Guide/TYPES-AND-CLASSES.md @@ -101,7 +101,7 @@ A type that must not be copied deletes the copy operations explicitly instead of - Overload an operator only when it means what it means for built-in types: `+` adds, `==` compares for equality, `[]` indexes. A reader must never wonder what `a << b` does to `a`. - **Default comparisons**: `operator==` and, when there is an order, `operator<=>`, both `= default` where memberwise - comparison is right. + comparison is right. [C++17 has neither](LANGUAGE.md#513-c17-projects). - Binary operators that are symmetric are hidden friends or non-members, so both operands convert the same way. - No overloads of `&&`, `||`, `,` or unary `&`. @@ -3,7 +3,7 @@ # Progmasoft C++ Style -Progmasoft C++ Style is a style guide for C++20. It says how code is named, laid out, structured and checked, and why, +Progmasoft C++ Style is a style guide for C++17 and C++20. It says how code is named, laid out, structured and checked, and why, so that a reader can move between files and projects without relearning the conventions each time. It is written for anyone who wants a complete, opinionated rule set to adopt. Progmasoft's own C++ projects follow it, @@ -27,7 +27,7 @@ left to the author. | [2. Formatting](Guide/FORMATTING.md) | the `.clang-format` profile, and what formatting leaves to the author | | [3. Naming](Guide/NAMING.md) | types, functions, variables, constants, namespaces, files, macros | | [4. Files and headers](Guide/FILES-AND-HEADERS.md) | extensions, `#pragma once`, includes, file size, the order inside a file | -| [5. Language](Guide/LANGUAGE.md) | C++20 features: `auto`, initialization, `const`, casts, integers, templates, lambdas | +| [5. Language](Guide/LANGUAGE.md) | Language versions and features: `auto`, initialization, `const`, casts, integers, templates, lambdas | | [6. Types and classes](Guide/TYPES-AND-CLASSES.md) | structs and classes, special members, inheritance, operators, enums | | [7. Errors](Guide/ERRORS.md) | exception-free code, `Expected` and `Error`, invariants, fatal defects | | [8. Ownership and memory](Guide/OWNERSHIP-AND-MEMORY.md) | RAII, smart pointers, views and their lifetimes, containers | @@ -42,7 +42,7 @@ records a deviation. [Contributing](CONTRIBUTING.md) explains how to propose a c ## The short version -- C++20, formatted by the [clang-format profile](Guide/FORMATTING.md#the-profile), checked by the +- C++17 or C++20, formatted by the [clang-format profile](Guide/FORMATTING.md#the-profile), checked by the [clang-tidy profile](Guide/TOOLING.md#132-the-clang-tidy-profile) with every warning an error. - `PascalCase` for types, functions and namespaces; `camelCase` for variables and parameters; `name_` for private data members; `kPascalCase` for constants and enumerators; `UPPER_SNAKE_CASE` for macros. |