There was the C standard library that could be consumed by C++ applications, the C++ frameworks specific to each compiler vendor that sadly are no longer a thing, and the C++ ARM de facto standard with only iostreams, being used as the initial discussion for what would become C++98, a decade later.
Many of C++ warts are related to this historical evolution, like how many variations of string, arrays and other collection classes do you want to use in a single project?
Yes, correct, what I meant is that you can still use many features like type_traits, bit_cast, initializer_list, span, array etc. Of course, std::string and friends are a bit no-no in very memory constrained cases.
> So current C++ standard library must be treated like part of the compiler implementation.
Indeed. Though even in C, compiler will assume C standard library is present unless you explicitly tell it not to (it optimizes calls to memcpy and will emit memset calls when initializing variables to 0)
The point I tried to make is that you cannot reasonably use modern features of C++ with your own standard library — the amount of undocumented internal compiler details you have to guess and match exactly is becoming unmanageable. And while -fno-rtti and -fno-exceptions still miraculously are supported by compilers (it is explicitly non-conforming C++ even in "freestanding" implementation, according to 16.4.2.5) and stop compiler from emitting references to std::, other features like allocators do not have an "off" switch.
The initializer_list is a good example. N4950 17.10 explicitly tells you there are multiple valid ways to implement it. If you guess incorrectly, your program will crash.
So current C++ standard library must be treated like part of the compiler implementation. It did not use to be like that.