This discussion is really off-topic, but whatever, it seems like something can be possibly learned from it.
Your wording strongly implies ... that C++ is somehow layered over C
Yes, I did not mean that, I should've written the next sentence on the new line to not create that confusion.
The fact that the first C++ compilers, historically speaking, were written in C seems quite irrelevant.
Let me rephrase what I've meant with the std::string example. If you want to understand my perspective, you should try to think about things as they are. What is std::string really? What does it do? What happens when you use it? When do you use it? What's the purpose of it in the place where you need to use it?
Now, hear me out: in majority of cases (I've read lots of codebases, majority of them are eye-bleeding), people think it's just a way to declare a string. Technically, it is. However, "string" is not a type, really. It's a container like a "vector". That means, that it has a bunch of things inside, that you can also use: could be functions, could be some other things.
When you care about efficiency (and the complexity of your program), you care about what you use, and what's the final output that you get after you feed your code to the compiler. Now, majority of people assume (or don't and they just don't know about that) that C++ probably has everything right and everything is good, because there are super smart people working on it, and you should trust the compiler no matter what; and they will defend any decision that C++ authors will make.
There's nothing really bad at implementing features similar to those of the "Modern C++". What matters is how they are implemented. C++, generally speaking, is inefficient by design. So, it's not that the programming language itself is horrible, but rather compilers. It's possible that someone would write a highly efficient C++ compiler that compiles 1M LOC/s and it has a "string" type, and if you want to use some additional features to do operations on them, you wouldn't need to include thousands of unnecessary lines of code to your generated program. But, today, this is not true with any C++ compiler (GNU C++, MSVC, ICC, etc.).
What people seem to miss, is that it's possible to use better implementations (that are available for free!) of many C++'s standard library functions, especially for data structures and algorithms. Now, if you take the "minimalism" of C, get rid of "classes" (there are structs), and use better implementations - wouldn't that be better than what C++ STD has to suggest? Practice shows, it is. And experts know that (that's why they are experts, not because they have X years of experience at a brand-level company, but because they know what they do and it was proven in practice).
How to understand my perspective? You should think about memory. And the code that your compiler produces. Now, apply the memory layout to your generated program and see what's going on. In most of the cases, where people happily use C++ with std::, what happens is that each call goes through a maze of branching. And what I'm trying to say is that that branching is unnecessary. Why would I use something like that, when I can not use it and perfectly do my job without any pain that people talk about all the time?
All in all, the reasons to not use these things are performance. You may not be in an agreement with me, because you may be one of the folks who are from the "solving problems without caring about efficiency" camp.
And let me actually provide you with an example:
Let's assume we're a beginner modern C++ programmer, who's enthusiastic about programming (so it's most likely that I will use Visual Studio with MSVC!). And we also want to use std::string. So, let's do that!
#include <iostream>
int main()
{
std::string str = "hello";
std::cout << str << std::endl;
}
The code above looks pretty much simple, we just ask the compiler to output "hello". Nothing seems suspicious about that. Now, let's step into our code and see where it goes for just std::string (ignoring ::cout and ::endl): basic_string(...)
constexpr explicit _Compressed_pair(...)
constexpr allocator() noexcept {}
constexpr explicit _Compressed_pair(...)
_String_val() noexcept : _Bx(), _Mysize(0), _Myres(0) {}
_Container_base12() noexcept : _Myproxy(nullptr) {}
_String_val() noexcept : _Bx(), _Mysize(0), _Myres(0) {}
_Bxty() noexcept {}
_String_val() noexcept : _Bx(), _Mysize(0), _Myres(0) {}
constexpr explicit _Compressed_pair(...)
basic_string(...)
_Alty& _Getal()
constexpr _Ty1& _Get_first() noexcept
constexpr allocator(const allocator<_Other>&) noexcept {}
_Container_proxy_ptr12(_Alloc& _Al_, _Container_base12& _Mycont)
_NODISCARD __declspec(allocator) _Ty\* allocate(_CRT_GUARDOVERFLOW const size_t _Count)
_NODISCARD constexpr size_t _Get_size_of_n(const size_t _Count)
__declspec(allocator) void\* _Allocate(const size_t _Bytes)
__declspec(allocator) static void\* _Allocate(const size_t _Bytes)
_NODISCARD constexpr _Ty\* _Unfancy(_Ty\* _Ptr) noexcept
_NODISCARD constexpr _Ty\* addressof(_Ty& _Val) noexcept
void _Construct_in_place(...
_NODISCARD constexpr _Ty\* addressof(_Ty& _Val)
_NODISCARD void\* _Voidify_iter(_Iter _It) noexcept
void _Tidy_init() noexcept
static _CONSTEXPR17 void assign(_Elem& _Left, const _Elem& _Right) noexcept
basic_string& assign(_In_z_ const _Elem\* const _Ptr)
_NODISCARD static _CONSTEXPR17 size_t length(_In_z_ const _Elem\* const _First)
basic_string& assign(_In_reads_(_Count) const _Elem\* const _Ptr, _CRT_GUARDOVERFLOW const size_type _Count)
value_type\* _Myptr() noexcept
bool _Large_string_engaged() const noexcept
_CSTD memmove(_First1, _First2, _Count \* sizeof(_Elem));
static _CONSTEXPR17 void assign(_Elem& _Left, const _Elem& _Right) noexcept
void _Release() noexcept
~_Container_proxy_ptr12()
And those are all functions.What if we were to use "const char*" instead, if our intentions were to just output a simple string? Nothing. It would not travel to any library, because it's not a library implementation. And if I were to make my own string handler, it wouldn't be as messy. Ah, the resulting code with "std::string" is 60KB (that's bonkers!), meanwhile with "const char*" it's 40KB (still bonkers!).
the implementation of the C++ standard library is more C-like than typical C++
Yes, I did not say that, and I did not think about that.
as much of an expert as you say
I never said that I'm an expert, though!