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

summaryrefslogtreecommitdiffhomepage
path: root/Guide
diff options
context:
space:
mode:
authorLeitwolf2026-10-31 13:01:49 +0300
committerGitHub2026-10-31 13:01:49 +0300
commitc0e89a73611f5730ff4d5172adb2a07be98d7b48 (patch)
tree7e32402fa9c06014328a27d7972c2fb1a9484352 /Guide
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
Diffstat (limited to 'Guide')
-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
6 files changed, 49 insertions, 9 deletions
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 `&`.