https://www.sandordargo.com/blog/2025/01/08/cpp26-unnamed-placeholders avatar Sandor Dargo's Blog On C++, software development and books * HOME * TAGS * ARCHIVES * BOOKS * SPEAKING * DAILY C++ * HI... * [become_a_p] Blog 2025 01 08 C++26: a placeholder with no name Post [ ] Cancel C++26: a placeholder with no name Sandor Dargo Jan 8 2025-01-08T00:00:00+01:00 4 min Let's continue exploring C++26. In this post, we are going to discuss a core language feature proposed by Corentin Jabot and Micheal Park in P2169R4. With the new standard we get a cool unnamed placeholder. Motivations By convention, when we have a variable whose value we don't want to use or care about, we often name it _. The problem is that with higher warning levels (-Wunused-variable), our compilation might fail because _ is unused. 1 int foo() { 2 return 42; 3 } 4 5 auto _ = foo(); 6 /* 7 error: unused variable '_' [-Werror,-Wunused-variable] 8 */ To avoid this problem, we must mark it [[maybe_unused]]. 1 int foo() { 2 return 42; 3 } 4 5 [[maybe_unused]] auto _ = foo(); // OK now But what if we want to ignore several of them? 1 int foo() { return 42; } 2 char bar() { return 'c'; } 3 4 [[maybe_unused]] auto _ = foo(); 5 [[maybe_unused]] auto _ = bar(); In this case, even [[maybe_unused]] doesn't help because _ is just a normal variable and is introduced twice. We can use std::ignore! 1 #include 2 int foo() { return 42; } 3 char bar() { return 'c'; } 4 5 std::ignore = foo(); 6 std::ignore = bar(); But even this solution won't work all the time. We cannot use it with structured bindings, which are probably the most often used place where _ is used as variable names. And if you want to use _ with various structured bindings in the same (nested) scope, you have to look for other solutions. 1 std::map> m{ 2 {1, {"one", "I", "foo"}}, {2, {"two", "II", "bar"}}, {3, {"three", "III", "baz"}}}; 3 4 for(const auto& [_, v]: m) { 5 const auto& [e, r, _] = v; // ERROR: error: redefinition of '_'! 6 std::cout << e << " in Roman format " << r << '\n'; 7 } The above piece of code will not compile, because we try to redefine _! In some cases, we can easily remove one of the ignored variables with the help of ranges! 1 #include 2 3 std::map> m{ 4 {1, {"one", "I", "foo"}}, {2, {"two", "II", "bar"}}, {3, {"three", "III", "baz"}}}; 5 6 for(const auto& v: m | std::views::values) { 7 const auto& [e, r, _] = v; 8 std::cout << e << " in Roman format " << r << '\n'; 9 } But this won't be possible all the time. In addition, there are some variables such as locks and scope_guards that are only used for their side effects. We don't want to store them in (not-so-)nicely named variables. The new solution The solution that is brought to us with the acceptance of P2169R4 is simple. We can use _ as a placeholder in the same scope as many times as we want. This solution is also similar to other languages' features or conventions and it's not unfamiliar at all from existing C++ practices. It already carries the meaning of "I don't want to use this variable". In more - but not too - technical terms, if we introduce _ as a variable, a non-static class member, a lambda capture or in a structured binding, it will implicitly get the [[maybe_unused]] attribute. In addition, we can also redeclare it as many times as we want it. On the other hand, if we try to use _ in any expression, the program is ill-formed! The new placeholder has certain limits, it cannot be used in template parameter lists or in requires clauses. For more details on the whys, refer to the accepted proposal The authors also investigated the effects on existing code. The library that might come into most of our minds is GMock, where _ is used to match any input passed to a function. There is little risk that this new feature will cause problems to GMock users as long as using namespace testing; appears before any declaration of _. This change has been already implemented in GCC 14 and Clang 18. Conclusion C++26 is going to bring us an unnamed placeholder, _, that can be redeclared as many times in the same scope as you need it. It is implicitely bears the [[maybe_unused]] attribute to avoid getting warnings on unused variables. You can already try this feature with a fresh version of GCC and Clang. Connect deeper If you liked this article, please * hit on the like button, * subscribe to my newsletter [yH5BAEAAAA] dev cpp cpp26 placeholder cleancode This post is licensed under CC BY 4.0 by the author. [yH5BAEAAAA] [yH5BAEAAAA] Share Recent Update * The big STL Algorithms tutorial: transform * My DEV birthday gift for you: DEV.to Analytics! * The best 8 books I read this year * The big STL Algorithms tutorial: modifying sequence operations - fill and generate * Real-World Bug Hunting by Peter Yarowski Trending Tags cpp books watercooler career tutorial cpp23 stl algorithms self-improvement management Contents Further Reading Oct 4, 2023 2023-10-04T00:00:00+02:00 Trip report: Dev Talks Cluj 2023 The last week of September I had the honour to share my thoughts in the heart of Transylvania about clean code and software quality at DevTalks Cluj. Over the last few years, DevTalks became a succ... Oct 11, 2023 2023-10-11T00:00:00+02:00 How to compare signed and unsigned integers in C++20? Comparing two numbers should be easy right? Maybe it should, yet it's not the case in C++ even if we constrain the comparison to the domain of integral numbers. If you try to compare a signed with... Oct 18, 2023 2023-10-18T00:00:00+02:00 My battle against signed/unsigned comparison: the most usual violations As we discussed last week, comparing numbers with different signs can be dangerous in C++. If you try to compare a signed with an unsigned integer, you might get a result that makes no sense if you... C++26: user-generated static_assert messages - Comments powered by Disqus. (c) 2025 Sandor Dargo. Some rights reserved. Powered by Jekyll with Chirpy theme. Trending Tags cpp books watercooler career tutorial cpp23 stl algorithms self improvement management