Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

forward declaration of std::string and std::wstring

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?

like image 601
Daniel Heilper Avatar asked May 05 '14 15:05

Daniel Heilper


2 Answers

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.

like image 58
Sebastian Redl Avatar answered Nov 07 '22 22:11

Sebastian Redl


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).

like image 7
utnapistim Avatar answered Nov 07 '22 22:11

utnapistim