June 1, 2026
BSL Support for C++23
Introduction
BSL provides an allocator-aware standard library in the bsl namespace,
together with aliases for standard library types, available across all
supported platforms and language modes back to C++03.
Over the past year, we have been working to align BSL with C++23. All changes
described here are available as of BDE 4.38.0. Where noted, individual
features are backported to older language modes; all other additions require a
platform that supports the C++23 standard library (indicated by
BSLS_LIBRARYFEATURES_HAS_CPP23_BASELINE_LIBRARY or one of the more
specific BSLS_LIBRARYFEATURES_HAS_CPP23_* macros described below).
For C++23 features not yet available in this release, see C++23 Features Planned for Future Releases.
Notable New Features
Additional feature test macros
BDE has added a number of new BSLS_LIBRARYFEATURES_HAS_CPP23_* feature
test macros (detailed in the Feature-Detection Macros section below). The most broadly useful is
BSLS_LIBRARYFEATURES_HAS_CPP23_BASELINE_LIBRARY, which indicates the
availability of a representative selection of C++23 standard library features
and is currently set on the following platforms:
GCC 13 (libstdc++ 13)
Clang compiling against libc++ version 18
Visual Studio 2022 update 17.6 / MSVC 19.36
Ranges-Aware Construction and Insertion for bsl Containers
All bsl sequence containers (bsl::vector, bsl::deque,
bsl::list, bsl::string), ordered associative containers
(bsl::map, bsl::set, bsl::multimap, bsl::multiset), and
unordered associative containers (bsl::unordered_map,
bsl::unordered_set, bsl::unordered_multimap,
bsl::unordered_multiset) now support C++23 ranges-aware construction and
insertion, backported to all language modes back to C++03.
Containers now support the bsl::from_range tag constructor and methods
such as append_range, assign_range, insert_range, and
push_range, accepting any type satisfying std::ranges::range directly.
A common pre-C++23 pain point was constructing a container from a temporary
range object: begin() and end() must be called on the same object, so
you could not pass a temporary directly to the iterator-pair constructor — a
named variable was required. The from_range constructor resolves this:
// Before: named variable required to keep the tokenizer alive
bdlb::Tokenizer tokenizer(text, " ");
bsl::vector<bsl::string_view> tokens(tokenizer.begin(), tokenizer.end());
// Now: pass directly using the from_range constructor
bsl::vector<bsl::string_view> tokens(bsl::from_range,
bdlb::Tokenizer(text, " "));
In C++20 and later, lazy range pipelines produce non-common ranges (where
the end sentinel type differs from the iterator type) that cannot be passed to
iterator-pair constructors without first converting them via
bsl::views::common. The new range-aware methods accept non-common ranges
directly:
// Before: views::common required to satisfy iterator-pair constructor
auto pipeline = source | bsl::views::filter([](int x) { return x > 0; })
| bsl::views::common;
positives.insert(positives.end(), pipeline.begin(), pipeline.end());
// Now: append_range accepts non-common ranges directly
positives.append_range(source | bsl::views::filter([](int x) { return x > 0; }));
The container adaptors bsl::stack, bsl::queue, and
bsl::priority_queue likewise gain from_range tag constructors and
push_range methods.
bsl::print and bsl::println: C++23 Print Facility
<bsl_print.h> provides bsl::print and bsl::println as a backport
of the C++23 <print> facility, available in all language modes back to
C++03. On platforms with a C++23 standard library these delegate to the
native implementation; elsewhere they are backed by BDE’s bslfmt formatter.
The following functions are provided:
bsl::print(fmt, args...)bsl::println(fmt, args...)bsl::vprint_nonunicode(fmt, args)bsl::vprint_nonunicode_buffered(fmt, args)bsl::vprint_unicode(fmt, args)bsl::vprint_unicode_buffered(fmt, args)
BDE deviates slightly from the standard here: in C++23, <ostream> includes
std::print overloads for output streams, but <bsl_ostream.h> does
not include the corresponding bsl::print overloads. Those are available
in the separate <bsl_print_ostream.h> header, which must be included
explicitly to avoid pulling the full formatting machinery into every
translation unit that uses <bsl_ostream.h>.
Monadic Operations for bsl::optional
bsl::optional now provides the C++23 monadic interface
(requires C++17 or later):
and_then(f)– appliesfto the contained value and returns its result (which must be absl::optional), or returns an empty optional if*thisis disengaged.or_else(f)– returns*thisif engaged, or callsf()and returns its result otherwise.transform(f)– appliesfto the contained value and wraps the result in a newbsl::optional, or returns empty if disengaged.
These operations are not yet backported to C++03/11/14.
bsl::visit() for Types Derived from bsl::variant
bsl::visit() now correctly handles arguments whose static type is a class
publicly derived from bsl::variant, rather than bsl::variant itself,
as required by C++23.
Heterogeneous Erasure for Associative Containers
All bsl ordered and unordered associative containers now support
heterogeneous erasure (C++23). When the container’s comparator or hash is
tagged as transparent, erase(key) accepts any type comparable to the
stored key type, eliminating unnecessary temporary key constructions.
bsl::basic_string::substr() &&
bsl::basic_string::substr() now has an rvalue-qualified overload. When
called on a temporary (or explicitly moved) string, this overload can avoid a
copy by moving the relevant portion of the source’s storage. This overload
requires C++11 (BSLS_COMPILERFEATURES_SUPPORT_REF_QUALIFIERS).
bsl::string::contains() and bsl::string_view::contains()
bsl::string and bsl::string_view now provide the C++23 contains()
member function, testing whether the string contains a given substring,
character, or string view.
bsl::string and bsl::string_view Construction from nullptr Prohibited
As required by C++23 (P2166), bsl::string
and bsl::string_view now have a deleted constructor taking
bsl::nullptr_t, making constructions such as:
bsl::string s(nullptr); // error: deleted
bsl::string_view v(nullptr); // error: deleted
a compile-time error rather than silent undefined behavior.
Because the deleted constructor takes bsl::nullptr_t, overload resolution
selects it for any null pointer constant — defined by the C++ standard as
an integer literal with value zero or a prvalue of type std::nullptr_t.
This covers nullptr, 0, NULL, and bsl::nullptr_t variables.
A const char* variable is not a null pointer constant, even if its
runtime value is null, and therefore does not select the deleted constructor:
bsl::string s(nullptr); // error: deleted
bsl::string t(0); // error: deleted
bsl::string u(NULL); // error: deleted
const char* p = nullptr;
bsl::string v(p); // still compiles; still undefined behavior
The deleted constructors use = delete, which requires C++11; in C++03
mode this protection is unavailable.
C++23 Features Planned for Future Releases
bsl::expected
bsl::expected<T, E> (P0323) is a vocabulary
type that holds either a value of type T or an error of type E,
providing a composable alternative to error codes or exceptions. A
BDE-native allocator-aware implementation is in progress.
bsl::move_only_function and bsl::copyable_function
bsl::move_only_function (P0288) is a
move-only general-purpose callable wrapper that avoids the unnecessary
copyability requirement of bsl::function.
bsl::copyable_function (P2548) is a
copyable wrapper with correct const-propagating call semantics: calling a
const bsl::copyable_function requires a const-qualified call
operator, unlike bsl::function. Both are in progress.
bsl::flat_map, bsl::flat_set, and Variants
bsl::flat_map, bsl::flat_set, bsl::flat_multimap, and
bsl::flat_multiset (P1222) are ordered
associative containers backed by contiguous storage (by default
bsl::vector), offering cache-friendly iteration at the cost of O(n)
insertion. Their addition is deferred pending GCC 15 availability on
BDE target platforms, which is required for thorough allocator-propagation
testing.
For users needing flat containers today, bdlc::FlatHashMap and
bdlc::FlatHashSet provide high-performance open-addressing hash tables
with flat (contiguous) storage, available in all language modes back to
C++03. Note that these are unordered containers and are not a direct
substitute for the sorted bsl::flat_map family.
Other Deferred Features
constexprsupport forbsl::optional,bsl::variant, andbsl::bitset— deferred pendingconstexpr-capable construction utilities in BDE.Range formatting via
bsl::format(formatting containers and views directly with"{}") — a partial backport supporting BDE containers is under investigation; full support for arbitrary ranges is expected to rely on the platform’s native C++23std::format.
Feature-Detection Macros
The following BSLS_LIBRARYFEATURES_HAS_CPP23_* macros were introduced or
are relevant to the features described in this article.
Macro |
Feature guarded |
|---|---|
|
Core C++23 library additions: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Native |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Summary of C++23 Features and Backporting
| Feature | C++23 | Backporting | ||||
|---|---|---|---|---|---|---|
| C++20 | C++17 | C++14 | C++11 | C++03 | ||
| Feature-detection macros (BSLS_LIBRARYFEATURES_HAS_CPP23_*) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| New standard library headers aliased (bsl_generator.h, bsl_mdspan.h, bsl_spanstream.h, bsl_stacktrace.h, bsl_stdfloat.h) |
✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| C++23 aliases added to existing bsl headers | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| bsl::print / bsl::println | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Ranges-aware construction / insertion for containers (from_range, append_range, insert_range, …) |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Ranges-aware construction / insertion for container adaptors (bsl::stack, bsl::queue, bsl::priority_queue) |
✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| bsl::string::contains() / bsl::string_view::contains() | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| bsl::basic_string::substr() && | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Heterogeneous erasure for associative containers | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Monadic operations for
bsl::optional (and_then, or_else, transform) |
✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| bsl::visit() for types derived from bsl::variant | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Construction from nullptr prohibited for bsl::string / bsl::string_view | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
Complete Description of Aliasing Changes
Aliasing: New headers added
The following headers were added to alias new C++23 standard library additions, and test drivers created:
Header file |
Types aliased |
|---|---|
|
bsl::generator; |
|
bsl::mdspan;bsl::extents;bsl::dextents;bsl::layout_left;bsl::layout_right;bsl::layout_stride;bsl::default_accessor; |
|
bsl::print;bsl::println;bsl::vprint_nonunicode;bsl::vprint_nonunicode_buffered;bsl::vprint_unicode;bsl::vprint_unicode_buffered; |
|
bsl::print; (ostream overload)bsl::println; (ostream overload)bsl::vprint_nonunicode;bsl::vprint_unicode; |
|
bsl::basic_spanbuf;bsl::basic_ispanstream;bsl::basic_ospanstream;bsl::basic_spanstream;bsl::spanbuf;bsl::ispanstream;bsl::ospanstream;bsl::spanstream;bsl::wspanbuf;bsl::wispanstream;bsl::wospanstream;bsl::wspanstream; |
|
bsl::stacktrace;bsl::stacktrace_entry;bsl::basic_stacktrace; |
|
bsl::float16_t;bsl::float32_t;bsl::float64_t;bsl::float128_t;bsl::bfloat16_t; |
Aliasing: Additions to existing headers
The following existing headers were enhanced with aliases to new C++23 standard library additions, with test drivers enhanced accordingly:
Header file |
Types aliased |
|---|---|
|
//
BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_SHIFTbsl::ranges::shift_left;bsl::ranges::shift_right;//
BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_STARTS_ENDS_WITHbsl::ranges::starts_with;bsl::ranges::ends_with;//
BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_FIND_LASTbsl::ranges::find_last;bsl::ranges::find_last_if;bsl::ranges::find_last_if_not;//
BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_CONTAINSbsl::ranges::contains;bsl::ranges::contains_subrange;//
BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_FOLDbsl::ranges::fold_left;bsl::ranges::fold_left_with_iter;bsl::ranges::fold_left_with_iter_result;bsl::ranges::fold_left_first;bsl::ranges::fold_left_first_with_iter;bsl::ranges::fold_left_first_with_iter_result;bsl::ranges::fold_right;bsl::ranges::fold_right_last;bsl::ranges::in_value_result;//
BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_IOTAbsl::ranges::out_value_result; |
|
//
BSLS_LIBRARYFEATURES_HAS_CPP23_BASELINE_LIBRARYbsl::byteswap; |
|
//
BSLS_LIBRARYFEATURES_HAS_CPP23_BASELINE_LIBRARYbsl::invoke_r;//
BSLS_LIBRARYFEATURES_HAS_CPP23_BIND_BACKbsl::bind_back; |
|
//
BSLS_LIBRARYFEATURES_HAS_CPP23_SPANSTREAMbsl::basic_spanbuf;bsl::basic_ispanstream;bsl::basic_ospanstream;bsl::basic_spanstream;bsl::spanbuf;bsl::ispanstream;bsl::ospanstream;bsl::spanstream;bsl::wspanbuf;bsl::wispanstream;bsl::wospanstream;bsl::wspanstream; |
|
//
BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_AS_CONSTbsl::const_iterator;bsl::const_sentinel;bsl::basic_const_iterator;bsl::make_const_iterator;bsl::make_const_sentinel;bsl::iter_const_reference_t; |
|
//
BSLS_LIBRARYFEATURES_HAS_CPP23_ALLOCATE_AT_LEASTbsl::allocation_result;//
BSLS_LIBRARYFEATURES_HAS_CPP23_OUT_PTRbsl::out_ptr;bsl::out_ptr_t;bsl::inout_ptr;bsl::inout_ptr_t;//
BSLS_LIBRARYFEATURES_HAS_CPP23_START_LIFETIME_ASbsl::start_lifetime_as;bsl::start_lifetime_as_array; |
|
//
BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_IOTAbsl::ranges::iota;bsl::ranges::iota_result; |
|
//
BSLS_LIBRARYFEATURES_HAS_CPP23_BASELINE_LIBRARYbsl::ranges::as_rvalue_view;bsl::ranges::chunk_by_view;bsl::ranges::repeat_view;bsl::views::as_rvalue;bsl::views::chunk_by;bsl::views::repeat;//
BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_TO_CONTAINERbsl::ranges::to;//
BSLS_LIBRARYFEATURES_HAS_CPP23_RANGE_ADAPTOR_CLOSUREbsl::ranges::range_adaptor_closure;//
BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_AS_CONSTbsl::ranges::const_iterator_t;bsl::ranges::const_sentinel_t;bsl::ranges::range_const_reference_t;bsl::ranges::constant_range;bsl::ranges::as_const_view;bsl::views::as_const;//
BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_CARTESIAN_PRODUCTbsl::ranges::cartesian_product_view;bsl::views::cartesian_product;//
BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_CHUNKbsl::ranges::chunk_view;bsl::views::chunk;//
BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_ENUMERATEbsl::ranges::enumerate_view;bsl::views::enumerate;//
BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_JOIN_WITHbsl::ranges::join_with_view;bsl::views::join_with;//
BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_SLIDEbsl::ranges::slide_view;bsl::views::slide;//
BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_STRIDEbsl::ranges::stride_view;bsl::views::stride;//
BSLS_LIBRARYFEATURES_HAS_CPP23_RANGES_ZIPbsl::ranges::adjacent_view;bsl::ranges::adjacent_transform_view;bsl::ranges::zip_view;bsl::ranges::zip_transform_view;bsl::views::adjacent;bsl::views::adjacent_transform;bsl::views::zip;bsl::views::zip_transform;//
BSLS_LIBRARYFEATURES_HAS_CPP23_GENERATORbsl::ranges::elements_of;//
BSLS_LIBRARYFEATURES_HAS_CPP23_CONTAINERS_RANGESbsl::from_range;bsl::from_range_t; |
|
//
BSLS_LIBRARYFEATURES_HAS_CPP23_BASELINE_LIBRARYbsl::is_scoped_enum;bsl::is_scoped_enum_v;//
BSLS_LIBRARYFEATURES_HAS_CPP23_IS_IMPLICIT_LIFETIMEbsl::is_implicit_lifetime;bsl::is_implicit_lifetime_v;//
BSLS_LIBRARYFEATURES_HAS_CPP23_REFERENCE_FROM_TEMPORARYbsl::reference_constructs_from_temporary;bsl::reference_constructs_from_temporary_v;bsl::reference_converts_from_temporary;bsl::reference_converts_from_temporary_v; |
|
//
BSLS_LIBRARYFEATURES_HAS_CPP23_BASELINE_LIBRARYbsl::to_underlying;bsl::unreachable;//
BSLS_LIBRARYFEATURES_HAS_CPP23_FORWARD_LIKEbsl::forward_like; |