Ch20.6: What Is Still Missing Today

中文(简体)

1. The Header List, and the Year Each Entry Arrived

A freestanding implementation must provide at least the headers on the standard's list. Here are the ones that matter for normal code, with the standard that added them, from cppreference's table:

HeaderStatusSince
<cstddef>AllC++98
<cfloat>, <climits>, <limits>AllC++98 / C++11
<cstdarg>, <cstdint>AllC++98 / C++11
<new>, <typeinfo>, <exception>AllC++98
<initializer_list>, <type_traits>, <atomic>AllC++11
<concepts>, <coroutine>, <bit>, <source_location>, <version>AllC++20
<utility>, <tuple>, <ratio>AllC++23
<memory>, <iterator>, <ranges>, <functional>PartialC++23
<cstdlib>PartialC++98
<array>, <cstring>, <string>, <cmath>, <system_error>, <charconv>, <algorithm>PartialC++26

Two things jump out. First, <utility> — where std::move lives — was not a freestanding header until C++23, twenty-five years after the language shipped. Second, look at the last row and notice that it is the row you need most.

2. The C++26 Hole

Those last entries are real standards work, adopted and voted in — for C++26. They are guarded by feature-test macros such as __cpp_lib_freestanding_array = 202311L, and they are behind a standard that was not published. So the honest state of std::array today is:

A three-element fixed-size array is the least demanding container in the language: no heap, no exceptions required by the interface, no allocation, no locale, no I/O. It has been in the standard since C++11 and it is still not a freestanding header in any published revision. That is the whole C++ freestanding story in one type.

3. What a Hosted Toolchain with -ffreestanding Actually Gives You

Measured on GCC 17's libstdc++, which is one of the better ones. Each line is a one-line file, compiled with -std=c++26 -ffreestanding -fsyntax-only:

OK    <cstddef>
OK    <utility>
OK    <array>
FAIL  <vector>      error: #error "This header is not available in freestanding mode."
FAIL  <string>      error: #error "This header is not available in freestanding mode."
OK    <string_view>
OK    <optional>
OK    <expected>
OK    <span>
FAIL  <cmath>       error: #error "This header is not available in freestanding mode."
FAIL  <iostream>    error: #error "This header is not available in freestanding mode."
FAIL  <print>       error: #error "This header is not available in freestanding mode."

Read the middle column: <string_view>, <optional>, <expected> and <span> work, and <cmath> — the C++ wrapper around a header that C has required in freestanding since 1989 — does not. That is not a considered portability policy; it is the cumulative result of thirty years of headers being written for hosted programs and gated afterwards.

And remember where this list came from: a hosted installation with a flag flipped (20.1). On a real bare-metal toolchain every single line would be fatal error: ... file not found (20.5).

4. The Three Tiers, and the One Nobody Argues About

TierMeaningWhat it means for your build
Required The standard says a freestanding implementation has it You can rely on it, on every conforming toolchain, forever
Vendor extension Your libstdc++/libc++ ships it anyway Works today, silently breaks on the next toolchain or the next board
Never vector, list, deque, map: "due to their dependencies on exceptions and heap", as cppreference puts it No amount of standardisation will change it — the dependency is the design

That last row is the interesting one, because it is not about scheduling. The standard library's containers report allocation failure by throwing, and they grow by allocating from a global heap. Those are not incidental properties; they are the interface. So the one part of the library that is genuinely useful for real programs is the part the standard has decided cannot be freestanding at all.

The conclusion is not "wait for C++29". It is that a freestanding program has to own its headers — decide which ones it will trust, on which toolchains, with which fallbacks — or use a library that already made that decision and can be built for the target. That is the argument for 20.13.

5. What the Toolchain Vendors Say About It

Three major implementations, three answers. The MSVC STL does support freestanding, and has for years. libstdc++ had "implementation and build issues before version 13" — cppreference's words — and works from GCC 13 on, partly. And libc++ does not support freestanding at all: on the clang side there is no freestanding configuration to target, which is why a bare-metal C++ build is the hardest one to get out of the Clang family.

So the state of the art is: one vendor supports it, one supports part of it from a recent version, and one does not support it at all. That is not a feature you can build a product on without checking; it is a feature you have to test on every toolchain you ship. Note also that cppreference's own note repeats the libc++ claim as if it applied to both C++ libraries of note, which is exactly the sort of second-hand summary you cannot use instead of checking.

Meanwhile the C freestanding list is four headers and has never had a compatibility problem, because it is a list of things the compiler cannot function without.