2

Possible Duplicates:
C++, removing #include<vector> or #include<string> in class header
Forward declare an STL container?

I want to forward declare std::string, by the way, can I forward declare a struct?

Community
  • 1
  • 1
Liu
  • 645
  • 2
  • 8
  • 16

3 Answers3

4

std::string is a typedef so you cannot just forward declare it. You could look up the exact declaration, forward declare that and define the typedef yourself, but then you'd also have to forward declare char_traits and allocator. So this should might work, although it's not supposed to*:

namespace std
{
  template< class T, class Traits, class Allocator >
  class basic_string;

  template< class T >
  struct char_traits;

  template< class T >
  class allocator;

  typedef basic_string< char, char_traits< char >, allocator< char > > string;
}

but in the end you're probably better off including . I'm also unsure whether these declarations are exactly the same on all platforms, not to mention the problems it would cause should the declaration in the string header ever change.

*see comment below

stijn
  • 34,664
  • 13
  • 111
  • 163
  • 3
    Undefined behavior: you're not allowed to put definitions or declarations in `std` except for specializations for user-defined types of standard function templates. Even if your definition matches your implementation's definition, the standard says behavior is undefined. So I'd say, "will work on most implementations" or "will work on X,Y and Z" rather than "should work". There's no "should" about it, other than that you "should" not do it ;-) – Steve Jessop Oct 02 '10 at 12:52
  • looked it up, you're right indeed. Which compilers follow the standard for this matter? – stijn Oct 02 '10 at 16:03
  • 1
    @stijn: well, they all follow the standard. Because the standard says that programs which do this have "undefined behavior" (as opposed to defining it as a language constraint), the implementation is allowed to do anything, including doing the thing you're hoping will happen. What I haven't seen is compilers issuing diagnostics, which they aren't required to do but which would be a nice way to alert people who try it without having seen that part of the standard. I guess it's so the headers can be supplied separately from the compiler (e.g. Dinkumware, STLPort) without generating warnings. – Steve Jessop Oct 02 '10 at 18:10
  • @Steve Would you please point to the relevant chapter/section of the standard? Can't find it... – Paul Michalik Oct 02 '10 at 23:07
  • Hm, strange, my comment was split in two parts... Anyway: As far as I know, there is nothing special with std:: namespace. You'd run into same problems with any other generic code with non-trivial type templates combined with typedefs to them. – Paul Michalik Oct 02 '10 at 23:16
  • @paul_71: 17.4.3.1/1. `string` is especially strange because it's a typedef, and that makes a difference in practice in the sense that stijn's code probably does work on a lot of implementations, where an incompatible forward-declaration might not. But as far as the standard is concerned, we could just as well be talking about `strlen`, and it would be UB to forward-declare that in `namespace std` too. – Steve Jessop Oct 02 '10 at 23:40
  • 1
    I was just wondering about that 'undefined behavior'. Technically, the behavior of forward declarations of types or signatures which are not compatible with their implementation should not lead to 'undefined behavior'. Either the forward declarations match and the program compiles and links, or there are conflicts which must generate either compile-time or link-time errors. This is independent of the used namespace. Still waiting for that pointer to relevant part of the standard. Anyway, there are examples where this was done wisely, consider the std::tr1 implementation delivered with boost. – Paul Michalik Oct 03 '10 at 10:55
2

in general so as to forward declare the class of a namespace you do it this way:

namespace MyOtherNamespace
{
    class MyForwardedClass;
}

namespace MyNamespace
{
    MyOtherNamespace::MyForwardedClass * pClass;
}

but I suspect there may be some limitation concerning std::, not sure though, I am going to check. Because I kind of remember some collisions due to typedefs...

Stephane Rolland
  • 38,876
  • 35
  • 121
  • 169
1

Simple answer: don't do it. Never try to 'forward declare' elements from the standard library (or from boost or cgal etc)... you will shooot yourself in the foot. The above post already states, that you'd need to forward declare the complete type definition. This can easily lead to conflicts on other platforms or different implementations of the standard library.

This is a traditional problem of c++. Unreflected includes of std or boost lead to inacceptable compilation times, wild propagation of errors from template instantiations and so on. I have seen it newly in one of our projects where people having no clue were at work. You have several choices to avoid or hide the dependencies:

  1. Don't expose these elements in your API, use (const) char*, for example ...
  2. Write generic code, which does not need to now the run-time type
  3. Write interfaces which encapsulate functionality of these elements and allows you to move the dependencies into source files.

The best variant would use a combination of all three.

Paul Michalik
  • 4,331
  • 16
  • 18