https://mariusbancila.ro/blog/2024/09/06/whats-new-in-c26-part-1/ Search for: [ ] Search Skip to content Marius Bancila's Blog About code. Mostly on C++ Menu * Home * About me * Works * Privacy Policy What's new in C++26 (part 1) Posted on September 6, 2024September 6, 2024 by Marius Bancila The C++26 version of the C++ standard is a work in progress, but a series of language and library features have been already added. Furthermore, some of them are already supported by Clang and GCC. One of these new changes was discussed in my previous article, Erroneous behaviour has entered the chat. In this post, we will look at several language features added in C++26. Specifying a reason for deleting a function Since C++11, we can declare a function as deleted, so that the compiler will prevent its use. This can be used to prevent the use of class special member functions, but also to delete any other function. A function can be deleted as follows (example from the proposal paper): class NonCopyable { public: // ... NonCopyable() = default; // copy members NonCopyable(const NonCopyable&) = delete; NonCopyable& operator=(const NonCopyable&) = delete; // maybe provide move members instead }; In C++26, you can specify a reason why this function is deleted: class NonCopyable { public: // ... NonCopyable() = default; // copy members NonCopyable(const NonCopyable&) = delete("Since this class manages unique resources, copy is not supported; use move instead."); NonCopyable& operator=(const NonCopyable&) = delete("Since this class manages unique resources, copy is not supported; use move instead."); // provide move members instead }; The reason for having this feature is to help API authors to provide tailored messages for the removal of a function, instead of just relying on the generic compiler error for using a deleted function. For more info see: P2573R2: = delete("should have a reason"); Placeholder variables with no name There are cases when a variable has to be declared but its name is never used. An example is structure bindings. Another is locks (like lock_guard), that are only used for their side-effects. In the future, another example could be pattern matching (for which several proposals exist). In C++26, we can use a single underscore (_) to define an unnamed variable. For instance, in the following example, unused is a variable that is not used: [[maybe_unused]] auto [data, unused] = get_data(); In C++26, the unused variable can be named _ (single underscore): auto [data, _] = get_data(); When the single underscore identifier is used for the declaration of a variable, non-static class member variable, lambda capture, or structure binding, the [[maybe_unused]] attribute is implicitly added, therefore, there is no need to explicitly use it. A declaration with the name _ is said to be name-independent if it declares: * a variable with automatic storage duration * a structure binding, but not in a namespace scope * a variable introduced by an init capture * a non-static data member The compiler will not emit warnings that a name-independent declaration is used or not. Moreover, multiple name-independent declarations can be used in the same scope (that is not a namespace scope): int main() { int _; _ = 0; // OK std::string _; // OK, because _ is a name-independent declaration _ = "0"; // Error: ambiguous reference to placeholder '_', which is defined multiple times } On the other hand, the following is not possible: int main() { int _; _ = 0; // OK static std::string _; // Error: static variables are not name-independent } The following is also not possible, because the declarations are in a namespace scope: namespace n { int f() {return 42;} auto _ = f(); // OK auto _ = f(); // Error: redefinition of _ } To learn more about this feature see: P2169: A nice placeholder with no name. Structured binding declaration as a condition A structure binding defines a set of variables that are bound to sub-objects or elements of their initializer. auto [position, length] = get_next_token(text, offset); A structure binding can appear in a for-range declaration, such as in the following example: for (auto [position, length] : tokenize(text, offset)) { std::println("pos {}, len {}", position, length); } On the other hand, variables can appear in the condition of an if, while, or for statement: if (auto it = std::find_if(begin(arr), end(arr), is_even); it != std::end(arr)) { std::println("{} is the 1st even number", *it); } However, structure bindings cannot be declared in the condition of an if, while, or for statement. That changes in C++26, which makes it possible: if(auto [position, length] = get_next_token(text, offset); position >= 0) { std::println("pos {}, len {}", position, length); } An interesting and very useful case is presented in the proposal paper (P0963). Consider the following C++26 example for using std::to_chars: if (auto result = std::to_chars(p, last, 42)) { auto [ptr, _] = result; // okay to proceed } else { auto [ptr, ec] = result; // handle errors } When the function succeeds, we are only interested in the ptr member of std::to_chars_result, which contains a pointer to the one-past-the-end pointer of the characters written. If the function fails, then we also need to look at the ec member (of the std::errc type) representing an error code. This code can be simplified with structure bindings, in C++26, as follows: if (auto [ptr, ec] = std::to_chars(p, last, 42)) { // okay to proceed } else { // handle errors } To learn more about this feature see: P0963: Structured binding declaration as a condition. user-generated static_assert messages The static_assert's second parameter, which is a string representing the error message, can now be a compile-time user-generated string-like object. The following example uses a hypothetical constexpr std::format, although this may also later appear in C++26: static_assert(sizeof(int) == 4, std::format("Expected 4, actual {}", sizeof(int))); To learn more about this feature see: P2471R3: user-generated static_assert messages. Share this: * Facebook * Twitter * Print * More * * Email * Reddit * Like this: Like Loading... CategoriesC++TagsC++, C++26 Post navigation PreviousPrevious post: Erroneous behaviour has entered the chat Leave a Reply Cancel reply This site uses Akismet to reduce spam. Learn how your comment data is processed. About me [marius2020] [cookbook3r] [templatesb] [learncspro] [cppchallen] [mvplogo180] Find me on: [twitter32] [linkedin32] [rss32] Archives September 2024 M T W T F S S 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 << Apr Follow me on Twitter My Tweets Recent Posts * What's new in C++26 (part 1) * Erroneous behaviour has entered the chat * Modern C++ Programming Cookbook - Third Edition * Formatting Text in C++: The Old and The New Ways * How to convert an enum to string in C++ * The curious case of error C2065: 'IID_InterfaceName': undeclared identifier * Notes on std::optional's monadic operations * Using Microsoft Edge in a native Windows desktop app - part 6 * Using Microsoft Edge in a native Windows desktop app - part 5 * How to make chunks of a range in C++23 Statistics Free counters Free counters! Meta * Log in * Entries feed * Comments feed * WordPress.org Proudly powered by WordPress Simplent Theme by Rafay %d bloggers like this: