The problem of the inability to forward declare std::string and std::wstring is often discussed. As I understand, the reason is that those types are typedefing of instantiation of template class basic_string:
namespace std {
typedef basic_string<char> string;
typedef basic_string<wchar_t> wstring;
}
And forward declaration of a typedef isn't allowed by the language.
Wouldn't it be better for the c++ standard using inheritance instead of typedef:
namespace std {
class string : public basic_string<char> {};
class wstring : public basic_string<wchar_t> {};
}
So that way we could forward declare std::string and std::wstring?
A "typedef derived class" is not equivalent to a real typedef.
Imagine I have a function that should work with both versions:
template <typename Ch>
void foo(const std::basic_string<Ch>& s) {
// do some stuff here
}
And the stuff I need to do includes calling 3rd party function bar
, which exists as overloads for std::string
and std::wstring
, but not as a template:
void bar(const std::string& s) {}
void bar(const std::wstring& s) {}
Then if you have a true typedef, that will just work. If you use inheritance instead, it will either fail to compile, or it will silently create copies of the strings to pass to bar
, which is a hidden performance trap.
Or take the substr
member function. It returns the same type as it is called on, but that means if it is a member of basic_string
, it doesn't return a string
or wstring
if those aren't true typedefs. That leads to all sorts of subtle issues.
Wouldn't be better for the c++ standard using inheritance instead of typedef [...]
No.
The std::basic_string is not meant to be inherited in any form. This limitation allows the implementation of a std::basic_string, that is much cheaper (faster) to create and destroy, as it has no virtual function table.
If you need std::[w]string to be defined, just #include
it.
Edit (answering comment)
One of the guiding principles of C++ (and the standard library) is "do not pay for what you do not use". This means the code is written in such a way, that you should not incur runtime costs for features you do not need.
Creating a std::string instance would be much more expensive if each instance had a virtual table (and this would make using std::string, prohibitive in performance-critical code).
Instead, std::string is intended as a fast, type-safe, RAII implementation of the C char*
mechanism. Similarly, you should not attempt to inherit from std::vector, list, map, shared_ptr, unique_ptr and so on.
If you really need a string base class, consider writing a your_namespace::[w]string_base
yourself (a trivial implementation would be one that encapsulates a std::[w]string
internally).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With