Three types of name lookups in C++ -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGLet's revisit a core concept in C++: how the compiler finds the names you use in your code. From qualified and unqualified name lookups to the special case of Argument-Dependent Lookup (ADL), understanding these mechanisms is essential for writing clear and correct C++ programs.

Three types of name lookups in C++

by Sandor Dargo

From the article:

Let’s get back to some basics this week and talk about name lookups in C++. In other words: when you refer to a symbol in your code, how does the compiler find it?

Essentially, we can differentiate between three kinds of lookups:

  • Qualified name lookup
  • Unqualified name lookup
  • Argument-Dependent Lookup (ADL)

Let’s explore them in that order.

Qualified Name Lookup

The term qualified refers to symbols that are explicitly scoped using the :: operator. In other words, these are names that appear to the right of a ::, such as x in a::b::x.

Before the compiler can perform a qualified name lookup, it must first resolve the left-hand side of the :: operator. This identifies the namespace or class being referenced.

Qualified name lookup is relatively simple: it only searches the explicitly named scope. It does not search enclosing or outer scopes.

Why does C++ think my class is copy-constructible when it can’t be copy-constructed? -- Raymond Chen

RaymondChen_5in-150x150.jpgIn C++, the presence of a user-declared (but not explicitly deleted) copy constructor is enough for the type to be considered copy-constructible by traits like std::is_copy_constructible. However, whether that constructor is instantiable is a separate matter—if it attempts to call a deleted base copy constructor, you'll still get a compile-time error when you actually try to use it.

Why does C++ think my class is copy-constructible when it can’t be copy-constructed?

by Raymond Chen

From the article:

Consider the following scenario:

template<typename T>
struct Base
{
    // Default-constructible
    Base() = default;

    // Not copy-constructible
    Base(Base const &) = delete;
};

template<typename T>
struct Derived : Base<T>
{
    Derived() = default;
    Derived(Derived const& d) : Base<T>(d) {}
};

// This assertion passes?
static_assert(
    std::is_copy_constructible_v<Derived<int>>);

Why does this assertion pass? It is plainly evident that you cannot copy a Derived<int> because doing so will try to copy the Base<int>, which is not copyable.

2025-07 Mailing Available

The 2025-07 mailing of new standards papers is now available.

 

WG21 Number Title Author Document Date Mailing Date Previous Version Subgroup
N5012 WG21 2025-06 Sofia Admin telecon minutes Nina Ranns 2025-06-08 2025-07 All of WG21
N5016 WG21 June 2025 Sofia Hybrid meeting Minutes of Meeting Nina Ranns 2025-07-08 2025-07 All of WG21
P0085R2 Oo... adding a coherent character sequence to begin octal-literals Axel Naumann 2025-06-06 2025-07 P0085R1 EWG Evolution,LEWG Library Evolution
P0085R3 Oo... adding a coherent character sequence to begin octal-literals Axel Naumann 2025-07-01 2025-07 P0085R2 EWG Evolution
P0085R3 Oo... adding a coherent character sequence to begin octal-literals Axel Naumann 2025-07-01 2025-07 P0085R2 EWG Evolution
P0085R3 Oo... adding a coherent character sequence to begin octal-literals Axel Naumann 2025-07-01 2025-07 P0085R2 EWG Evolution
P0085R3 Oo... adding a coherent character sequence to begin octal-literals Axel Naumann 2025-07-01 2025-07 P0085R2 EWG Evolution
P0085R3 Oo... adding a coherent character sequence to begin octal-literals Axel Naumann 2025-07-01 2025-07 P0085R2 CWG Core
P0260R18 C++ Concurrent Queues Detlef Vollmann 2025-06-17 2025-07 P0260R17 LWG Library
P0260R19 C++ Concurrent Queues Detlef Vollmann 2025-06-18 2025-07 P0260R18 LWG Library
P0870R6 A proposal for a type trait to detect narrowing conversions Giuseppe D'Angelo 2025-06-17 2025-07 P0870R5 SG6 Numerics,LEWG Library Evolution,LWG Library
P0870R7 A proposal for a type trait to detect narrowing conversions Giuseppe D'Angelo 2025-06-17 2025-07 P0870R6 SG6 Numerics,LEWG Library Evolution,LWG Library
P0876R21 fiber_context - fibers without scheduler Oliver Kowalke 2025-07-13 2025-07 P0876R20 CWG Core,LWG Library
P1040R8 std::embed and #depend JeanHeyd Meneide 2025-06-22 2025-07 P1040R7 EWG Evolution
P1306R5 Expansion statements Dan Katz 2025-06-20 2025-07 P1306R4 All of WG21
P2079R10 Parallel Scheduler Lucian Radu Teodorescu 2025-06-25 2025-07 P2079R9 LWG Library
P2079R9 Parallel Scheduler Lucian Radu Teodorescu 2025-06-26 2025-07 P2079R8 LWG Library
P2319R5 Prevent path presentation problems Victor Zverovich 2025-06-17 2025-07 P2319R4 LWG Library
P2414R8 Pointer lifetime-end zap proposed solutions Paul E. McKenney 2025-06-18 2025-07 P2414R7 LEWG Library Evolution,LWG Library
P2414R9 Pointer lifetime-end zap proposed solutions Paul E. McKenney 2025-07-11 2025-07 P2414R8 EWG Evolution,LEWG Library Evolution
P2664R11 Proposal to extend std::simd with permutation API Daniel Towner 2025-06-20 2025-07 P2664R10 LWG Library
P2781R9 std::constexpr_wrapper Zach Laine 2025-06-17 2025-07 P2781R8 LWG Library
P2876R3 Proposal to extend std::simd with more constructors and accessors Daniel Towner 2025-06-17 2025-07 P2876R2 LWG Library
P2929R1 simd_invoke Daniel Towner 2025-06-19 2025-07 P2929R0 LEWG Library Evolution
P2996R13 Reflection for C++26 Barry Revzin 2025-06-20 2025-07 P2996R12 CWG Core,LWG Library
P3008R6 Atomic floating-point min/max Gonzalo Brito Gadeschi 2025-06-19 2025-07 P3008R5 LWG Library
P3044R2 sub-string_view from string Michael Florian Hava 2025-06-19 2025-07 P3044R1 LWG Library
P3045R6 Quantities and units library Mateusz Pusz 2025-06-19 2025-07 P3045R5 SG6 Numerics,SG16 Unicode,LEWGI SG18: LEWG Incubator,LEWG Library Evolution
P3060R3 Add std::views::indices(n) Weile Wei 2025-06-18 2025-07 P3060R2 LWG Library
P3091R4 Better lookups for `map` , `unordered_map`, and `flat_map` Pablo Halpern 2025-06-20 2025-07 P3091R3 LEWG Library Evolution,LWG Library
P3096R10 Function Parameter Reflection in Reflection for C++26 Adam Lach 2025-06-17 2025-07 P3096R9 CWG Core,LWG Library
P3096R11 Function Parameter Reflection in Reflection for C++26 Adam Lach 2025-06-19 2025-07 P3096R10 EWG Evolution,LEWG Library Evolution,CWG Core,LWG Library
P3096R12 Function Parameter Reflection in Reflection for C++26 Adam Lach 2025-06-20 2025-07 P3096R11 CWG Core,LWG Library
P3100R3 Implicit contract assertions Timur Doumler 2025-07-03 2025-07 P3100R2 EWG Evolution
P3104R4 Bit permutations Jan Schultke 2025-06-28 2025-07 P3104R3 SG6 Numerics,LWG Library
P3111R7 Atomic Reduction Operations Gonzalo Brito Gadeschi 2025-06-18 2025-07 P3111R6 CWG Core,LWG Library
P3111R8 Atomic Reduction Operations Gonzalo Brito Gadeschi 2025-06-19 2025-07 P3111R7 LWG Library
P3149R11 async_scope -- Creating scopes for non-sequential concurrency Ian Petersen 2025-06-19 2025-07 P3149R10 LWG Library
P3179R9 C++ parallel range algorithms Ruslan Arutyunyan 2025-05-28 2025-07 P3179R8 LWG Library
P3211R1 views::flat_map Hewill Kang 2025-07-04 2025-07 P3211R0 SG9 Ranges,LEWG Library Evolution,LWG Library
P3216R1 views::slice Hewill Kang 2025-06-28 2025-07 P3216R0 SG9 Ranges,LEWG Library Evolution,LWG Library
P3220R1 views::take_before Hewill Kang 2025-06-23 2025-07 P3220R0 SG9 Ranges,LEWG Library Evolution,LWG Library,Direction Group
P3223R2 Making std::istream::ignore less surprising Jonathan Wakely 2025-06-20 2025-07 P3223R1 LWG Library
P3248R4 Require [u]intptr_t Gonzalo Brito Gadeschi 2025-06-19 2025-07 P3248R3 LWG Library
P3290R3 Integrating Existing Assertions With Contracts Joshua Berne 2025-07-11 2025-07 P3290R2 SG22 Compatibility,LEWG Library Evolution
P3293R3 Splicing a base class subobject Barry Revzin 2025-06-20 2025-07 P3293R2 CWG Core,LWG Library
P3347R3 Invalid/Prospective Pointer Operations Paul E. McKenney 2025-07-11 2025-07 P3347R2 CWG Core
P3348R4 C++26 should refer to C23 not C17 Jonathan Wakely 2025-06-19 2025-07 P3348R3 SG6 Numerics,LWG Library
P3383R3 mdspan.at() Stephan Lachnit 2025-06-17 2025-07 P3383R2 LWG Library
P3394R4 Annotations for Reflection Daveed Vandevoorde 2025-06-20 2025-07 P3394R3 All of WG21
P3411R3 `any_view` Hui Xie 2025-06-18 2025-07 P3411R2 SG9 Ranges,LEWG Library Evolution
P3433R1 Allocator Support for Operation States Dietmar Kuehl 2025-06-19 2025-07 P3433R0 LWG Library
P3439R3 Chained comparisons: Safe, correct, efficient Herb Sutter 2025-06-19 2025-07 P3439R2 EWG Evolution
P3440R1 Add n_elements named constructor to std::simd Daniel Towner 2025-06-13 2025-07 P3440R0 LEWG Library Evolution
P3480R6 std::simd is a range Matthias Kretz 2025-06-17 2025-07 P3480R5 LWG Library
P3481R4 std::execution::bulk() issues Lucian Radu Teodorescu 2025-06-17 2025-07 P3481R3 SG1 Concurrency and Parallelism,LEWG Library Evolution,LWG Library
P3481R5 std::execution::bulk() issues Lucian Radu Teodorescu 2025-06-18 2025-07 P3481R4 SG1 Concurrency and Parallelism,LEWG Library Evolution,LWG Library
P3491R3 define_static_{string,object,array} Barry Revzin 2025-06-20 2025-07 P3491R2 CWG Core,LWG Library
P3503R3 Make type-erased allocator use in promise and packaged_task consistent Nicolas Morales 2025-06-19 2025-07 P3503R2 LWG Library
P3540R2 #embed Parameter offset JeanHeyd Meneide 2025-06-05 2025-07 P3540R1 CWG Core
P3552R3 Add a Coroutine Task Type Dietmar Kühl 2025-06-20 2025-07 P3552R2 All of WG21
P3557R3 High-Quality Sender Diagnostics with Constexpr Exceptions Eric Niebler 2025-07-04 2025-07 P3557R2 LWG Library
P3560R2 Error Handling in Reflection Barry Revzin 2025-06-20 2025-07 P3560R1 LWG Library
P3566R2 You shall not pass `char*` - Safety concerns working with unbounded null-terminated strings Marco Foco, Joshua Kriegshauser, Alexey Shevlyakov, Giuseppe D'Angelo 2025-06-15 2025-07 P3566R1 LEWGI SG18: LEWG Incubator,SG23 Safety and Security,LEWG Library Evolution
P3566R2 You shall not pass `char*` - Safety concerns working with unbounded null-terminated strings Marco Foco, Joshua Kriegshauser, Alexey Shevlyakov, Giuseppe D'Angelo 2025-06-15 2025-07 P3566R1 LEWGI SG18: LEWG Incubator,SG23 Safety and Security,LEWG Library Evolution
P3570R2 optional variants in sender/receiver Fabio Fracassi 2025-06-18 2025-07 P3570R1 LWG Library
P3601R0 Slides for P3407R1 Brian Bi 2025-06-17 2025-07 EWG Evolution
P3642R1 Carry-less product: std::clmul Jan Schultke 2025-06-03 2025-07 P3642R0 SG6 Numerics,LEWGI SG18: LEWG Incubator
P3642R2 Carry-less product: std::clmul Jan Schultke 2025-07-02 2025-07 P3642R1 LEWG Library Evolution
P3647R0 Slides for P3642R1 Jan Schultke 2025-06-18 2025-07 SG6 Numerics,LEWGI SG18: LEWG Incubator
P3655R2 zstring_view Peter Bindels 2025-06-15 2025-07 P3655R1 LEWG Library Evolution
P3663R2 Future-proof `submdspan-mapping` Mark Hoemmen 2025-07-13 2025-07 P3663R1 LWG Library
P3668R2 Defaulting Postfix Increment and Decrement Operations Matthew Taylor 2025-07-13 2025-07 P3668R1 CWG Core
P3669R2 Non-Blocking Support for `std::execution` Detlef Vollmann 2025-06-19 2025-07 P3669R1 SG1 Concurrency and Parallelism,LEWG Library Evolution
P3687R1 Final Adjustments to C++26 Reflection Dan Katz 2025-06-18 2025-07 P3687R0 EWG Evolution,LEWG Library Evolution,CWG Core,LWG Library
P3688R1 ASCII character utilities Jan Schultke 2025-06-28 2025-07 P3688R0 SG16 Unicode
P3690R1 Consistency fix: Make simd reductions SIMD-generic Olaf Krzikalla 2025-06-17 2025-07 P3690R0 LWG Library
P3691R1 Reconsider naming of the namespace for "std::simd" Matthias Kretz 2025-06-16 2025-07 P3691R0 LWG Library
P3692R1 How to Avoid OOTA Without Really Trying Paul E. McKenney 2025-07-10 2025-07 P3692R0 SG1 Concurrency and Parallelism
P3697R1 Minor additions to C++26 standard library hardening Konstantin Varlamov 2025-06-20 2025-07 P3697R0 LEWG Library Evolution,LWG Library
P3699R1 Rename `conqueue_errc` Detlef Vollmann 2025-06-16 2025-07 P3699R0 LEWG Library Evolution
P3705R1 A Sentinel for Null-Terminated Strings Eddie Nolan 2025-06-18 2025-07 P3705R0 SG9 Ranges,LEWG Library Evolution
P3705R2 A Sentinel for Null-Terminated Strings Eddie Nolan 2025-06-18 2025-07 P3705R1 SG9 Ranges,LEWG Library Evolution
P3709R1 Reconsider parallel ranges::rotate_copy and ranges::reverse_copy Ruslan Arutyunyan 2025-06-02 2025-07 P3709R0 SG9 Ranges,LEWG Library Evolution
P3709R2 Reconsider parallel ranges::rotate_copy and ranges::reverse_copy Ruslan Arutyunyan 2025-06-17 2025-07 P3709R1 SG9 Ranges,LEWG Library Evolution
P3711R1 Safer StringViewLike Functions for Replacing char* strings Marco Foco 2025-06-19 2025-07 P3711R0 SG23 Safety and Security,LEWG Library Evolution
P3713R0 2025-05 Library Evolution Poll Outcomes Inbal Levi 2025-07-15 2025-07 All of WG21
P3718R0 Fixing Lazy Sender Algorithm Customization, Again Eric Niebler 2025-06-28 2025-07 LEWG Library Evolution,LWG Library
P3719R0 std::is_vector_bool_reference Yuxuan Chen 2025-05-20 2025-07 LEWGI SG18: LEWG Incubator,LEWG Library Evolution
P3721R0 Slides for P3639R0 Jan Schultke 2025-06-03 2025-07 SG22 Compatibility
P3722R0 Slides for P3568R1 Jan Schultke 2025-05-27 2025-07 SG22 Compatibility
P3724R0 Integer division Jan Schultke 2025-06-05 2025-07 SG6 Numerics,LEWG Library Evolution
P3725R0 Filter View Extensions for Input Ranges Nicolai Josuttis 2025-06-19 2025-07 SG9 Ranges,LEWG Library Evolution,LWG Library
P3725R1 Filter View Extensions for Input Ranges Nicolai Josuttis 2025-06-23 2025-07 P3725R0 SG9 Ranges,LEWG Library Evolution,LWG Library
P3726R0 Adjustments to Union Lifetime Rules Barry Revzin 2025-07-13 2025-07 EWG Evolution,CWG Core
P3727R0 Update Annex E based on Unicode 15.1 UAX #31 Steve Downey 2025-06-11 2025-07 SG16 Unicode,CWG Core
P3729R0 Aligning span and string_view Michael Florian Hava 2025-06-23 2025-07 LEWG Library Evolution
P3730R0 Slides for P3104R3 Jan Schultke 2025-06-04 2025-07 LEWG Library Evolution
P3731R0 #embed Preprocessor Parameter Order JeanHeyd Meneide 2025-06-05 2025-07 SG22 Compatibility,EWG Evolution
P3732R0 Numeric Range Algorithms Ruslan Arutyunyan 2025-06-27 2025-07 SG1 Concurrency and Parallelism,SG9 Ranges
P3733R0 More named universal character escapes Jan Schultke 2025-06-28 2025-07 SG16 Unicode
P3734R0 Not all predicates must be regular Jan Schultke 2025-06-14 2025-07 SG9 Ranges
P3735R0 partial_sort_n, nth_element_n Jan Schultke 2025-06-28 2025-07 SG9 Ranges
P3736R0 Slides against P2971R3 - No implication for C++ Jan Schultke 2025-06-27 2025-07 EWG Evolution
P3737R0 std::array is a wrapper for an array! Jan Schultke 2025-06-11 2025-07 LEWG Library Evolution
P3738R0 Make std::make_from_tuple SFINAE friendly Yihan Wang 2025-06-10 2025-07 LEWG Library Evolution
P3739R0 Standard Library Hardening - using std::optional Jarrad J Waterloo 2025-06-10 2025-07 LWG Library
P3739R1 Standard Library Hardening - using std::optional Jarrad J Waterloo 2025-06-10 2025-07 P3739R0 LWG Library
P3740R0 Last chance to fix std::nontype Jan Schultke 2025-06-14 2025-07 LEWG Library Evolution
P3740R1 Last chance to fix std::nontype Jan Schultke 2025-06-19 2025-07 P3740R0 LEWG Library Evolution
P3741R0 views::set_operations Hewill Kang 2025-06-21 2025-07 SG9 Ranges
P3742R0 C++ Standard Library Ready Issues to be moved in Sofia, Jun. 2025 Jonathan Wakely 2025-06-13 2025-07 All of WG21
P3745R0 Rebuttal to P1144R13 Pablo Halpern 2025-07-02 2025-07 EWG Evolution,LEWG Library Evolution
P3746R0 LEWG Slides for P3637R0 Inherit std::meta::exception from std::exception Nevin Liber 2025-06-16 2025-07 LEWG Library Evolution
P3747R0 Call side return type deduction Thomas Mejstrik 2025-06-17 2025-07 EWGI SG17: EWG Incubator
P3748R0 Inspecting exception_ptr works should be constexpr. Hana Dusíková 2025-06-18 2025-07 LEWG Library Evolution
P3749R0 Slides in response to P3655R2 - Concerns regarding std::zstring_view Jan Schultke 2025-06-27 2025-07 LEWG Library Evolution
P3752R0 Core Language Working Group "ready" Issues for the June, 2025 meeting Jens Maurer 2025-06-20 2025-07 CWG Core
P3753R0 Slides for P3740R0 - Last chance to fix std::nontype Jan Schultke 2025-06-20 2025-07 LEWG Library Evolution
P3753R1 Slides for P3740R1 - Last chance to fix std::nontype Jan Schultke 2025-06-20 2025-07 P3753R0 LEWG Library Evolution
P3754R0 Slides for P3100R2 presentation to EWG Timur Doumler 2025-06-20 2025-07 EWG Evolution
P3757R0 Remove value-type invocability requirement from indirect unary callable concepts Hewill Kang 2025-06-21 2025-07 SG9 Ranges,LEWG Library Evolution,LWG Library
P3760R0 Presentation: constexpr 'Parallel' Algorithms Oliver Rosten 2025-06-21 2025-07 LEWG Library Evolution
P3763R0 Remove redundant reserve_hint members from view classes Hewill Kang 2025-06-21 2025-07 SG9 Ranges,LEWG Library Evolution,LWG Library
P3764R0 A utility function for propagating the most significant bit Jan Schultke 2025-07-15 2025-07 SG6 Numerics
P3765R0 Deprecate implicit conversion from bool to character types Jan Schultke 2025-07-12 2025-07 EWG Evolution
P3769R0 Clarification of placement new deallocation Lauri Vasama 2025-06-22 2025-07 EWG Evolution,CWG Core
P3771R0 constexpr mutex, locks, and condition variable Hana Dusíková 2025-06-30 2025-07 SG1 Concurrency and Parallelism,EWG Evolution,LEWG Library Evolution
P3772R0 std::simd overloads for bit permutations Jan Schultke 2025-06-28 2025-07 SG6 Numerics
P3774R0 Rename std::nontype, and make it broadly useful Jan Schultke 2025-07-15 2025-07 LEWG Library Evolution
P3778R0 Fixing `type_order` template definition Gašper Ažman 2025-07-03 2025-07 LEWG Library Evolution,LWG Library
P3780R0 Detecting bitwise trivially relocatable types Giuseppe D'Angelo 2025-07-10 2025-07 EWG Evolution,LEWG Library Evolution
P3781R0 is_*_type should imply is_type Xavier Bonaventura 2025-07-05 2025-07 SG20 Education,EWG Evolution
P3784R0 range-if Michael Florian Hava 2025-07-10 2025-07 EWGI SG17: EWG Incubator
P3785R0 Library Wording Changes for Defaulted Postfix Increment and Decrement Operators Matthew Taylor 2025-07-13 2025-07 LWG Library
P3787R0 Adjoints to "Enabling list-initialization for algorithms": uninitialized_fill Giuseppe D'Angelo 2025-07-10 2025-07 LEWG Library Evolution,LWG Library
P3788R0 Fixing `std::complex` binary operators Mateusz Pusz 2025-07-11 2025-07 SG6 Numerics,LEWG Library Evolution
P3790R0 Pointer lifetime-end zap proposed solutions: Bag-of-bits pointer class Paul E. McKenney 2025-07-13 2025-07 LEWG Library Evolution
P3791R0 constexpr deterministic random Hana Dusíková 2025-07-15 2025-07 LEWG Library Evolution
P3792R0 Why `constant_wrapper` is not a usable replacement for `nontype` Bronek Kozicki 2025-07-13 2025-07 LEWG Library Evolution,LWG Library
P3793R0 Better shifting Brian Bi 2025-07-15 2025-07 SG6 Numerics
P3794R0 An idea or two on renaming the nontype tag Zhihao Yuan 2025-07-13 2025-07 LEWG Library Evolution
P3795R0 Miscellaneous Reflection Cleanup Barry Revzin 2025-07-15 2025-07 EWG Evolution
P3796R0 Coroutine Task Issues Dietmar Kühl 2025-07-15 2025-07 SG1 Concurrency and Parallelism,LEWG Library Evolution,LWG Library
P3798R0 The unexpected in std::expected Alex Kremer 2025-07-14 2025-07 LEWGI SG18: LEWG Incubator,LEWG Library Evolution,LWG Library
P3799R0 2025-07 Library Evolution Polls Inbal Levi 2025-07-15 2025-07 LEWG Library Evolution
P3801R0 Concerns about the design of std::execution::task Jonathan Müller 2025-07-15 2025-07 LEWG Library Evolution
P3802R0 Poor Functions Daveed Vandevoorde 2025-07-15 2025-07 EWG Evolution,LEWG Library Evolution

Returning several values from a function in C++ (C++23 edition) -- Daniel Lemire

RkWx2Fr8_400x400.jpgWhile C++ doesn’t have native syntax for returning multiple values like some other languages, modern C++ offers powerful tools to accomplish the same goal. With features like std::tuple, structured bindings, std::expected, and std::optional, handling multiple return values—and even error codes—has become both clean and expressive.

Returning several values from a function in C++ (C++23 edition)

by Daniel Lemire

From the article:

Many programming languages such as the Go programming language are designed to make it easy to return several values at once from a function. In Go, it is often used to return an optional error code. The C++ programming language does not have a built-in support for returning several values. However, several standard types can serve the same purpose. If you need to return two values, you can use an std::pair instance. If you need to return two or more values, an std::tuple instance will do. With recent C++ standards, it works really well!

Suppose we want to compute a division with a string error message when one is trying to divided by zero:

std::tuple<int,std::string> divide(int a, int b) {
 if (b == 0) {
 return {0, "Error: Division by zero"};
 }
 return {a / b, "Success"};
}

This approach works nicely. The code is clear and readable.

You might be concerned that we are fixing the type (int). If you want to write one function for all integer types, you can do so with concepts, like so:

Constructing Containers from Ranges in C++23 -- Sandor Dargo

SANDOR_DARGO_ROUND.JPGStarting from C++23, standard containers support a new set of constructor overloads. These constructors take a std::from_range tag, a range and an optional allocator. These from_range constructors make it easier to construct containers from ranges, helping make C++ code more concise, more expressive, and less error-prone.

Constructing Containers from Ranges in C++23

by Sandor Dargo

From the article:

I’ve written plenty on this blog about standard algorithms, but far less about ranges. That’s mostly because, although I’ve had production-ready compilers with C++20 ranges since late 2021, the original ranges library lacked a few key capabilities.

The biggest gap was at the end of a pipeline: you could transform data lazily, but you couldn’t drop the result straight into a brand-new container. What you got back was a view; turning that view into, say, a std::vector still required the old iterator-pair constructor.

C++23 fixes that in two complementary ways:

  • std::to (an adaptor that finishes a pipeline by converting to a container), and
  • from_range constructors on every standard container.

Today we’ll focus on the second improvement, because it’s the one you can implement in your own types, too.

The from_range constructor

Every standard container now supports a new set of constructors that make integration with ranges smoother — the so-called from_range constructors.

These constructors allow you to build a container directly from a range, rather than from a pair of iterators.

C++ Insights now uses Clang 20 -- Andreas Fertig

me.pngTime flies—C++ Insights just turned 7! To celebrate, I’ve upgraded the tool to Clang 20, unlocking even more C++23 and C++26 features for you to explore.

C++ Insights now uses Clang 20

by Andreas Fertig

From the article:

size_t

For a long time now, when you used size_t or std::size_t the resulting transformation kept the name. It did not expand to the underlying machine-specific date type. To be honest, that was more like a happy accident. Clang 20 came with two changes to libc++

The first https://github.com/llvm/llvm-project/commit/d6832a611a7c4ec36f08b1cfe9af850dad32da2e modularized <cstddef> for better internal structuring, avoiding too much content to be included. This patch was followed by a second one: https://github.com/llvm/llvm-project/commit/5acc4a3dc0e2145d2bfef47f1543bb291c2b866a. This one now made an interesting change.

Previously, libc++ defined std::size_t as

1
using ::size_t _LIBCPP_USING_IF_EXISTS; 

As the second patch highlighted, this required including the operating systems <stddef.h>. In the spirit of reducing unnecessary includes the line was changed to:

1
using size_t = decltype(sizeof(int)); 

This is an easy C++ solution to get the proper data type for size_t. Which is great. Yet, the AST nodes of the two versions look different. Previously, the operating system (macOS in this case) defined in its header:

1
typedef unsigned long size_t; 

Well, with the new version, the transformation no longer stops at size_t but expands it all down to unsigned long. This probably should have been the case from the beginning, but I liked that tests and transformations did not change across platforms in this specific case. However, there are other instances where the transformation did yield different output on different platforms, so I accept this one.

 

What’s New for C++ Developers in Visual Studio 2022 17.14 -- Sy Brand

RE1Mu3b.pngVisual Studio 2022 version 17.14 is now generally available! This post summarizes the new features you can find in this release for C++. You can download Visual Studio 2022 from the Visual Studio downloads page or upgrade your existing installation by following the Update Visual Studio Learn page.

What’s New for C++ Developers in Visual Studio 2022 17.14

by Sy Brand

From the article:

We’ve made a myriad of fixes and improvements to the MSVC compiler and standard library. See C++ Language Updates in MSVC in Visual Studio 2022 17.14 for a full list of changes on the compiler side, and the STL Changelog for all the standard library updates.

Compiler

We’ve added support for several C++23 features, which are available under the /std:c++latest and /std:c++23preview flags.

You can now omit () in some forms of lambdas that previously required them, thanks to P1102R2:

auto lambda = [] constexpr { }; //no '()' needed after the capture list
We implemented if consteval, with which you can run different code depending on whether the statement is executed at compile time or run time. This is useful for cases where your run time version can be heavily optimized with compiler intrinsics or inline assembly that are not available at compile time:
constexpr size_t strlen(char const* s) {
    if consteval {
        // if executed at compile time, use a constexpr-friendly algorithm
        for (const char *p = s; ; ++p) {
            if (*p == '\0') {
                return static_cast<std::size_t>(p - s);
            }
        }
    } else {
        // if executed at run time, use inline assembly
        __asm__("SSE 4.2 magic");
    }
}

C++26: Erroneous Behaviour -- Sandor Dargo

logo.pngC++’s undefined behaviour impacts safety. Sandor Dargo explains how and why uninitialised reads will become erroneous behaviour in C++26, rather than being undefined behaviour.

C++26: Erroneous Behaviour

by Sandor Dargo

From the article:

If you pick a random talk at a C++ conference these days, there is a fair chance that the speaker will mention safety at least a couple of times. It’s probably fine like that. The committee and the community must think about improving both the safety situation and the reputation of C++.

If you follow what’s going on in this space, you are probably aware that people have different perspectives on safety. I think almost everybody finds it important, but they would solve the problem in their own way.

A big source of issues is certain manifestations of undefined behaviour. It affects both the safety and the stability of software. I remember that a few years ago when I was working on some services which had to support a 10× growth, one of the important points was to eliminate undefined behaviour as much as possible. One main point for us was to remove uninitialized variables which often lead to crashing services.

Thanks to P2795R5 by Thomas Köppe, uninitialized reads won’t be undefined behaviour anymore – starting from C++26. Instead, they will get a new behaviour called ‘erroneous behaviour’.

The great advantage of erroneous behaviour is that it will work just by recompiling existing code. It will diagnose where you forgot to initialize variables. You don’t have to systematically go through your code and let’s say declare everything as auto to make sure that every variable has an initialized value. Which you probably wouldn’t do anyway.

Writing Senders -- Lucian Radu Teodorescu

logo.pngSenders/receivers can be used to introduce concurrency. Lucian Radu Teodorescu describes how to implement senders.

Writing Senders

by Lucian Radu Teodorescu

From the article:

If people are just using frameworks based on std::execution, they mainly need to care about senders and schedulers. These are user-facing concepts. However, if people want to implement sender-ready abstractions, they also need to consider receivers and operation states – these are implementer-side concepts. As this article mainly focuses on the implementation of sender abstractions, we need to discuss these two concepts in more detail.

A receiver is defined in P2300 as “a callback that supports more than one channel” [P2300R10]. The proposal defines a concept for a receiver, unsurprisingly called receiver. To model this concept, a type needs to meet the following conditions:

  • It must be movable and copyable.
  • It must have an inner type alias named receiver_concept that is equal to receiver_t (or a derived type).
  • std::execution::get_env() must be callable on an object of this type (to retrieve the environment of the receiver).

A receiver is the object that receives the sender’s completion signal, i.e., one of set_value()set_error(), or set_stopped(). As explained in the December 2024 issue [Teodorescu24], a sender may have different value completion types and different error completion types. For example, the same sender might sometimes complete with set_value(int, int), sometimes with set_value(double), sometimes with set_error(std::exception_ptr), sometimes with set_error(std::error_code), and sometimes with set_stopped(). This implies that a receiver must also be able to accept multiple types of completion signals.