This repository implements std::optional extensions targeting C++26. The beman.optional library aims to evaluate the stability, the usability, and the performance of these proposed changes before they are officially adopted by WG21 into the C++ Working Draft. Additionally, it allows developers to use these new features before they are implemented in major standard library compilers.
Implements: std::optional<T&> (P2988R12) and
Give std::optional Range Support (P3168R2).
Status: Production ready. API may undergo changes.
beman.exemplar is licensed under the Apache License v2.0 with LLVM Exceptions.
Full runable examples can be found in examples/ - please check ./examples/README.md.
The next code snippet shows optional range support added in Give std::optional Range Support(P3168R2):
#include <beman/optional/optional.hpp>
...
beman::optional::optional<int> empty_opt{};
for ([[maybe_unused]] const auto& i : empty_opt) {
// Should not see this in console.
std::cout << "\"for each loop\" over C++26 optional: empty_opt\n";
}
beman::optional::optional<int> opt{26};
for (const auto& i : opt) {
// Should see this in console.
std::cout << "\"for each loop\" over C++26 optional: opt = " << i << "\n";
}Full code can be found in ./examples/range_loop.cpp. Build and run instructions in ./examples/README.md. Or try it on Compiler Explorer: range_loop.cpp@Compiler Explorer.
The next code snippet shows optional reference support added in std::optional<T&>
(P2988):
#include <beman/optional/optional.hpp>
...
struct Cat { ... };
beman::optional::optional<Cat&> find_cat(std::string) { return {}; }
beman::optional::optional<Cat&> do_it(Cat& cat) { return { cat }; }
beman::optional::optional<Cat&> api() {
beman::optional::optional<Cat&> cat = find_cat("Fido");
return cat.and_then(do_it);
}
beman::optional::optional<Cat&> cat = api();
Full code can be found in ./examples/optional_ref.cpp. Build and run instructions in ./examples/README.md. Or try it on Compiler Explorer: optional_ref.cpp@Compiler Explorer.
Source is licensed with the Apache 2.0 license with LLVM exceptions
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Documentation and associated papers are licensed with the Creative Commons Attribution 4.0 International license.
// SPDX-License-Identifier: CC-BY-4.0
The intent is that the source and documentation are available for use by people implementing their own optional types as well as people using the optional presented here as-is.
The README itself is licensed with CC0 1.0 Universal. Copy the contents and incorporate in your own work as you see fit.
// SPDX-License-Identifier: CC0-1.0
This is a modern C++ project which can be compiled with the latest C++ standards (C++20 or later).
Default build: C++23. Please check etc/${compiler}-flags.cmake.
This project is mainly tested on Ubuntu 22.04 and Ubuntu 24.04, but it should be as portable as CMake is. This project has no C or C++ dependencies.
Build-time dependencies:
cmakeninja,make, or another CMake-supported build system- CMake defaults to "Unix Makefiles" on POSIX systems
Example of installation on Ubuntu 24.04:
# Install tools:
apt-get install -y cmake make ninja-build
# Example of toolchains:
apt-get install \
g++-14 gcc-14 gcc-13 g++-13 \
clang-18 clang++-18 clang-17 clang++-17Build GoogleTest dependency from github.com
If you do not have GoogleTest installed on your development system, you may optionally configure this project to download a known-compatible release of GoogleTest from source and build it as well.
cmake -B build -S . -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=./cmake/use-fetch-content.cmakeThe precise version of GoogleTest that will be used is maintained in
./lockfile.json.
Full set of supported toolchains can be found in .github/workflows/ci.yml.
This project strives to be as normal and simple a CMake project as possible. This build workflow in particular will work, producing a static beman_optional library, ready to package:
# List available preset configurations:
$ cmake --workflow --list-presets
Available workflow presets:
"system"
"gcc-14"
"gcc-13"
"clang-18"
"clang-17"
# Run examples:
$ cmake --workflow --preset gcc-14
cmake --workflow --preset gcc-14
Executing workflow step 1 of 3: configure preset "gcc-14"
...
-- Build files have been written to: /path/to/repo/.build/gcc-14
Executing workflow step 2 of 3: build preset "gcc-14"
ninja: no work to do.
Executing workflow step 3 of 3: test preset "gcc-14"
Test project /path/to/repo/.build/gcc-14
Start 1: OptionalTest.TestGTest
1/... Test #1: OptionalTest.TestGTest ........................... Passed 0.00 sec
...
Start x: RangeSupportTest.RangeConcepts
.../... Test #x: RangeSupportTest.RangeConcepts ................... Passed 0.00 sec
Start x+1: RangeSupportTest.IteratorConcepts
.../... Test #x+1: RangeSupportTest.IteratorConcepts ................ Passed 0.00 sec
...
100% tests passed, 0 tests failed out of ...
Total Test time (real) = 0.09 secThis should build and run the tests with GCC 14 with the address and undefined behavior sanitizers enabled.
CI current build and test flows:
# Configure build: default build production code + tests (OPTIONAL_ENABLE_TESTING=ON by default).
$ cmake -G "Ninja Multi-Config" \
-DCMAKE_CONFIGURATION_TYPES="RelWithDebInfo;Asan" \
-DCMAKE_TOOLCHAIN_FILE=etc/clang-19-toolchain.cmake \
-B .build -S .
-- The CXX compiler identification is Clang 19.0.0
...
-- Build files have been written to: /path/to/optional/.build
# Build.
$ cmake --build .build --config Asan --target all -- -k 0
...
[30/30] Linking CXX executable ... # Note: 30 targets here (including tests).
# Run tests.
$ ctest --build-config Asan --output-on-failure --test-dir .build
Internal ctest changing into directory: /path/to/optional/.build
Test project /path/to/optional/.build
...
100% tests passed, 0 tests failed out of 82
Total Test time (real) = 0.67 secBy default, we build and run tests. You can provide -DOPTIONAL_ENABLE_TESTING=OFF and completely disable building tests:
# Configure build: build production code, skip tests (OPTIONAL_ENABLE_TESTING=OFF).
$ cmake -G "Ninja Multi-Config" \
-DCMAKE_CONFIGURATION_TYPES="RelWithDebInfo;Asan" \
-DCMAKE_TOOLCHAIN_FILE=etc/clang-19-toolchain.cmake \
-DOPTIONAL_ENABLE_TESTING=OFF \
-B .build -S .
-- The CXX compiler identification is Clang 19.0.0
...
-- Build files have been written to: /path/to/optional/.build
# Build.
$ cmake --build .build --config Asan --target all -- -k 0
...
[15/15] Linking CXX executable ... # Note: 15 targets here (tests were not built).
# Check that tests are not built/installed.
$ ctest --build-config Asan --output-on-failure --test-dir .build
Internal ctest changing into directory: /path/to/beman.optional/.build
Test project /path/to/beman.optional/.build
No tests were found!!!Various linting tools are configured and installed via the pre-commit framework. This requires a working python environment, but also allows the tools, such as clang-format and cmake-lint, to be versioned on a per project basis rather than being installed globally. Version changes in lint checks often means differences in success or failure between the versions in CI and the versions used by a developer. By using the same configurations, this problem is avoided.
In order to set up a python environment, using a python virtual environment can simplify maintaining different configurations between projects. There is no particular dependency on a particular python3 version.
python3 -m venv .venv
. .venv/bin/activate && python3 -m pip install --upgrade pip setuptools wheel
. .venv/bin/activate && python3 -m pip install pip-tools
. .venv/bin/activate && python3 -m piptools sync requirements.txt
. .venv/bin/activate && python3 -m piptools sync requirements-dev.txt
. .venv/bin/activate && exec bashThis will create the venv, install the python and python development tools, and run bash with the PATH and other environment variables set to use the venv preferentially.
pre-commit run -aThis will download and configure the lint tools specified in .pre-commit-config.yaml.
There is also a Makefile that will automate this process and keep everything up to date.
make lintLatest revision(s) of the papers can be built / found at:
- give-std-optional-range-support for
Give *std::optional* Range Support (P3168)- issue: #1831
- LEWG:
- Reviewed in Tokyo 2024.
- Forwarded by LEWG April electronic poll to LWG.
- LWG:
- Reviewed and approved in Saint Louis 2024.
- ./papers/P2988/README.md for
std::optional<T&> (P2988).- issue: #1661
- LEWG:
- Reviewed in Tokyo 2024.
- Forwarded by LEWG in 2025 in Hagenberg.