10

The standard library includes an <iosfwd> header, that (forward) declares all streams including any typedefs and defines the char_traits template, including the specializations.

Sadly, there is no such <stlfwd> header that (forward) declares all the common STL datatypes and functions like vector, map, less, sort, etc. Even more sadly, user code is not allowed to add such declarations / typedefs to the std namespace, as per

§17.4.3.1 [lib.reserved.names] p1:

It is undefined for a C + + program to add declarations or definitions to namespace std or namespaces within namespace std unless otherwise specified. A program may add template specializations for any standard library template to namespace std.

Yep, that covers the case of (forward) declarations, even if the types already exist in the standard library. Of course, most (all?) compilers will behave perfectly normal even if one adds such declarations, but strictly and language lawyer speaking, it is undefined behaviour. I find this especially tedious for typedefing standard containers, like:

// how to forward declare map and string?

typedef std::map<std::string, std::string> Attributes;

Now, can this be considered a defect?

I mean both the non-existence of a <stlfwd> header (or better, <stdfwd>, covering <iosfwd> too) and the ban on declarations already existing in the standard library.

Also, according to this question, if one (forward) declares the standard container, algorithms and functors / functionals exactly as demanded by the standard, the code should be perfectly valid (if it weren't for the ban of user-made declarations in the std namespace), because implementations aren't allowed to add any hidden/defaulted template parameters.

I am asking this because I'm thinking of eventually submitting a defect report regarding this.

Community
  • 1
  • 1
Xeo
  • 129,499
  • 52
  • 291
  • 397
  • Would such a header actually be beneficial? – James McNellis Jun 11 '11 at 03:07
  • @James McNellis Yes- it would mean that compilers would not need to take the time to repeatedly parse the full definition of the STL for compilation units that only use the STL by pointer or reference. It would reduce the physical dependencies between the STL and the client code, meaning that a change to the implementation of the STL would require less client code to be recompiled. – Mankarse Jun 11 '11 at 03:44
  • @Mankarse I would say changes to the standard library implementation are so rare that forcing a recompile isn't a real issue. But can you elaborate on your first point a bit more? I just have a hard time imagining a real-life scenario where you wouldn't need the full definition if you need it at all in a translation unit. – Mark B Jun 11 '11 at 03:47
  • @Mankarse: If the Standard Library implementation changed, I don't think I'd trust the compiler not to do a full recompile. Even if this is a concern, that's what precompiled headers are for. That said, I doubt that there would be substantial gain: the cost of lexing and parsing a couple of headers is almost certainly tiny relative to the cost of the rest of the compilation process (especially when you consider template instantiation). (I don't have this problem, though; 99.9% of my code ends up in headers anyway since I follow the "if it's not a template, it must not be general enough" rule) – James McNellis Jun 11 '11 at 04:02
  • @Mark B point taken - it is pretty rare, but it is inconvenient and inconsistent in the cases that it does occur. It's hard to describe a non-contrived example in 500 chars, but I can imagine 2 situations at least. 1) you have a class that is constructed by one part of the programme from a standard container, but used in another part without knowledge of that container (would be better to use Iterators, I know, but imagine this is in a shared library). 2) You have a class that is constructed by a factory, the factory takes a standard container by reference and passes it through. – Mankarse Jun 11 '11 at 04:21
  • 1
    @James McNellis - I totally agree with the "everything in a template" philosophy, but having worked on a legacy system with total recompile times of several hours I can tell you that physical dependencies do become important for large systems. – Mankarse Jun 11 '11 at 04:26

1 Answers1

7

What would be the purpose of forward declaring say less or sort or really any other algorithm? If you're passing a general purpose algorithm around it will almost certainly be as a template type and not need a forward declaration at all.

That leaves us with the container types. There are definitely cases where forward declarations of them would be useful but I suspect that it was simply decided that as each container definition is relatively simple (compared to iostreams) it would be preferable to just use the full include rather than a <containerfwd> include for example.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
Mark B
  • 95,107
  • 10
  • 109
  • 188
  • The problem comes with typedefs of the standard containers, especially. Say you want a `typedef std::map Attribues;`, how would you forward declare it? :/ – Xeo Jun 11 '11 at 03:46
  • @Xeo: I think the point Mark is making is that you just don't forward declare it. – Billy ONeal Jun 11 '11 at 03:57
  • 1
    @Xeo - If you need to forward declare it, don't use a typedef but perhaps a `struct Attributes` which can be elaborated later in another module. – Bo Persson Jun 11 '11 at 04:04