2

Let's say I have a header file with a class that uses std::string.

#include <string>

class Foo
{
     std::string Bar;

     public:

     // ...
}

The user of this header file might not want std::string to be included in his/her project. So, how do I limit the inclusion to just the header file?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Maxpm
  • 24,113
  • 33
  • 111
  • 170

4 Answers4

11

The user of your class must include <string>, otherwise their compiler will not know how big a Foo object is (and if Foo's constructors/destructors are defined inline, then the compiler also won't know what constructor/destructor to call for the string member).

This is indeed an irritating side-effect of the C++ compilation model (basically inherited intact from C). If you want to avoid this sort of thing entirely, you probably want to take a look at the PIMPL idiom.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • 2
    To whoever downvoted - This seems like a perfectly reasonable answer. Is there anything about it that you disagree with in particular? – templatetypedef Feb 19 '11 at 00:15
  • 1
    the person writing the header file is not REQUIRED to put the required #includes in thier header. If it is not included then it becomes the responsibility of the user of the header file to also include any required header files, which while doable for small projects, is completely unweildly for most projects. Although thinking about it, it can be useful in the general sense to override the default include to have the user specify a type compatable alternative (yes in the example above it would need to have a std namespace and string type.) – diverscuba23 Feb 19 '11 at 00:16
  • 2
    @diverscuba23- In this case, the header would be required if the `std::string` were a direct data member because the compiler needs to know the size of the object. You can get away with not including the file if you only need the type as a function argument, or if you just use a pointer to it, but in this particular instance you *must* include the header or the code won't compile. – templatetypedef Feb 19 '11 at 00:21
  • @diver: I didn't say that it's the responsibility of the header author to do the `#include`. However, what I did say was that the `#include` must happen *somewhere*. – Oliver Charlesworth Feb 19 '11 at 00:24
  • @diver: The idea of a "type-compatible alternative" is nonsensical! It must be *identical*, in which case you may as well use the original. – Oliver Charlesworth Feb 19 '11 at 00:26
  • I see that now after reading it again. and yes, PIMPL is really the way to provide alternative implementations. Can you provide me an edit so I can undown vote you? – diverscuba23 Feb 19 '11 at 00:27
5

Basically, you don't. Once you've included a file, all of the entities from that file are available for the remainder of the translation unit.

The idiomatic way to hide this sort of dependency is to rely on the pimpl idiom.

That said, why would code using Foo care that <string> was included? All of its entities are in the std namespace (well, except that <string> might include some of the C Standard Library headers, but generally you should code with the expectation that the C Standard Library headers might be included by any of the C++ Standard Library headers).

James McNellis
  • 348,265
  • 75
  • 913
  • 977
1

I don't see how this can be done, or if it's possible in c++. The reason being: when the compiler sees the member of type "std::string", it must know what is the type in order to know its size. This information can only be obtained by looking into the class definition in a .h file.

One way the users can use a different string class in their source, is by using "using" construct:

//This is how users can use an adt with same name but in different namespaces

    using std::string;
    string bar = "there";


    using my_own_lib::string;
    string bar1 = "here";
Viren
  • 2,161
  • 22
  • 27
  • Using different definitions for member variables of a particular class in different places would lead to an unholy mess, AKA *undefined behaviour*. – Oliver Charlesworth Feb 19 '11 at 00:38
  • I completely agree with you on that, but the original question was their any way to do that? So i just proposed a mechanism using c++ construct what would be a possible approach. so why downvote it? AFA one is using that construct correctly, their should not be an "undefined behavior" – Viren Feb 19 '11 at 01:00
  • On a second reading, I realise I misinterpreted your answer. In fact, what you are saying is perfectly reasonable! If you make an edit to your answer, then I will be able to remove the downvote. – Oliver Charlesworth Feb 19 '11 at 11:41
  • @Oli: Thank you. :-) I formatted the code and added a comment. – Viren Feb 19 '11 at 22:13
0

You can't do that. If the user doesn't want to include std::string, then he or she should not use that class at all. std::string will have to be included in the project in order to link your class correctly.

Daniel Gallagher
  • 6,915
  • 25
  • 31
  • "link" as well, even when using PIMPL. Though I suppose `basic_string` is a template, isn't it, so it will be instantiated and linked correctly even if it's not included in the project explicitly (except in this class). – Daniel Gallagher Feb 19 '11 at 00:15
  • Indeed! There is no linking required in this case. Furthermore, `#include` doesn't affect linking, period. – Oliver Charlesworth Feb 19 '11 at 00:30
  • @Oli: I suppose I'm confused by the OP's use of "might not want `std::string` included". I thought he was referring to including a portion of the standard library, not the `` header. Hence, my discussion of linking. – Daniel Gallagher Feb 19 '11 at 00:34