consider this translation unit:
#include <map>
#include <string>
int main()
{
std::map<std::string, std::size_t> mp;
mp.insert(std::make_pair("hello", 42));
}
There are two things in this translation unit that are bothering me, and they are
I have just assumed that <cstddef>
and <utility>
must have been #include
d by <string>
and <map>
.
How rightful is this assumption? At least for make_pair
I think there's a pretty strong guarantee because map member interfaces use std::pair
. For std::size_t
there is no formal guarantee but still it is very very very likely that it is available as soon as you include map
or string
. The stylistic question number one is Would you explicitly include <cstddef>
and <utility>
in this translation unit?
This part partly deals with the uncertaintly of some header being already included. However, there's the second part of the question. Suppose we have this
//f.h
#ifndef BIG_F_GUARD
#define BIG_F_GUARD
#include <string>
std::string f();
#endif
//f.cpp
#include "f.h"
std::string f()
{
std::string s;
return s;
}
Second question is: Would you explicitly #include <string>
into f.cpp?
I think I made my question clear. Btw. both questions are followed by a big WHY
:) Thanks.
In the first case, I probably wouldn't but I should, if I want my code to be properly portable. There's no requirement that map::size_type
is size_t
, so there's no necessity for <map>
to include a definition of size_t
. For that matter, size_t
can be a type alias rather than a distinct type, so even if size_type
is size_t
, it needn't have been defined in <map>
using that name. So as you say, it's likely but not guaranteed that <map>
includes <cstddef>
.
In the second case, I definitely wouldn't, because I know I don't need to. IMO a .cpp file is entitled to rely on the headers included by its corresponding .h file, since you kind of expect that if you modify the .h file you potentially need to modify the .cpp file too -- change an interface implies change its implementation, most of the time. And even if you feel I'm not entitled, I can always document that f.h includes <string>
, in which case I can rely on that.
Regarding <utility>
, I don't know whether <map>
is allowed to define std::pair
(because it needs it) without defining std::make_pair
(which is from the same standard header, and for the sake of argument let's say it isn't needed to define <map>
). This would be possible if the implementation's version of <utility>
itself includes a bunch of other files, for different bits, and <map>
just includes the bit it needs. Specific permission is given for headers to include other headers, but I don't know whether specific permission is given for headers to put things in namespace std
without including the whole of the corresponding header. The thing is, in practice it is very difficult to notice that you've forgotten a standard include in these cases, because implementations don't check for you, and that's why I know that in practice I'd quite likely not do it. Luckily it should be any easy fix for anyone porting to an implementation with different header dependencies.
What I tend to do, and it's not necessarily the right thing to do, is to include all the files I need to get the module to compile. The only problem with this is that when dependencies change, you can end up with code included which isn't necessarily used. However a good compiler will normally deal with this.
There's no need to include <string>
in your .cpp file however, because it's included through the header file. The contents of any included header files essentially get 'pasted' into your cpp file.
Hope this helps!
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