Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorLeitwolf2026-10-31 13:01:49 +0300
committerGitHub2026-10-31 13:01:49 +0300
commitc0e89a73611f5730ff4d5172adb2a07be98d7b48 (patch)
tree7e32402fa9c06014328a27d7972c2fb1a9484352
parent8d1fb4807edc7920fbecd0554c9c61625827e19c (diff)
parent1f5458322669301f62599c1ec5dacb77b5dc2d8d (diff)
downloadprogmasoft-cpp-main.tar.gz
Merge pull request #1 from Progmasoft/docs/cpp17-and-cpp20HEADmain
Cover C++17 as well as C++20
-rw-r--r--ADOPTING.md2
-rw-r--r--CHANGELOG.md4
-rw-r--r--Guide/C-INTERFACES.md4
-rw-r--r--Guide/ERRORS.md2
-rw-r--r--Guide/FORMATTING.md2
-rw-r--r--Guide/LANGUAGE.md44
-rw-r--r--Guide/TOOLING.md4
-rw-r--r--Guide/TYPES-AND-CLASSES.md2
-rw-r--r--README.md6
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 `&`.
diff --git a/README.md b/README.md
index 554d86a..f7444f5 100644
--- a/README.md
+++ b/README.md
@@ -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.