0

I am reading from here : Can std::string be used without #include <string>?, <iostream> is calling <string>. But I do not see any includes of <string> in Standard library header <iostream> from c++ standard: https://en.cppreference.com/w/cpp/header/iostream. In <iostream> is only included <ios>, <streambuf>, <istream> and <ostream> according to that documentation. So this code works (file foo.cpp):

#include <iostream>

int main(){
    std::cout << "enter srting\n";
    std::string out; //std::string should not be included according to standard documentation
    std::cin >> out;
    std::cout << "test, " << out;
}

But I have to try to see dependecies generated from gcc:

cc -H foo.cpp |& vim -

and the output is (I have regex out files with string in it):

. /usr/include/c++/8/iostream
..... /usr/include/c++/8/bits/stringfwd.h
...... /usr/include/c++/8/string
....... /usr/include/c++/8/bits/basic_string.h
........ /usr/include/c++/8/ext/string_conversions.h
....... /usr/include/c++/8/bits/basic_string.tcc

So I can see that in the end, many "string" headers are indeed included

  1. (so should I trust that documentation, when the did not mentioned <string> header in "Includes" list of <iostream>?).

Some of them are deeper on the #include stack (term from gcc manual), which brings me to question,

  1. what calls what? And what is the "true" header, that define std::string of them? (is it /usr/include/c++/8/bits/basic_string.h?...)

from this question Why does omission of "#include <string>" only sometimes cause compilation failures?, they mentioned:

Some compilers on some platforms may on some time of the month compile even though you failed to include the header

But from the upper output of the "string headers", there is multiple of them , so how's possible for a compiler to compile only sometimes? Which of these headers are really important for successful compilation?

  1. How to orient in cpp headers, which are meaningful for compiler, and could be tracked their "#include stack" (i.e. other meaningful headers)?

EDIT: If it depends on my specific implementation of my stdlib++, then I want to know how can I determine from source whether that inclusion is made before I try to compile. Not by "If it compiles, then it works".

milanHrabos
  • 2,010
  • 3
  • 11
  • 45
  • I would like a little bit more elaborated answer, not just "recommendation". I know I should include headers of object I am using, but I want to know, why it "sometimes" compiles. I would like to know what "truly" headers are important and explanation of it (i.e. what compiler does). I gave an effort to this question, please do you as well. – milanHrabos Jun 28 '20 at 19:53
  • it is actually required (though very obscure) by the C++ standard that #include makes the definition of the class std::string available. It does not require that it does so by including any specific header. It's been a long-standing issue with beginners using Visual Studio where they'd only include iostream and find that they can use std::string, but not add/compare them or call std::getline. – Cubbi Jun 29 '20 at 14:52
  • Just selecting lines from the `-H` output which match string is highly deceptive; you lose information about the actual path to each header printed. For what it's worth, the inclusion path to `string` is `iostream->ostream->ios->bits/ios_base.h->bits/locale_classes.h->string` (gcc version 8). I used this little awk script to get that: `{d[length($1)]=$0} /\/string$/ {for (i=1;i<=length($1);++i) print d[i]; exit;}` – rici Jun 29 '20 at 15:05

3 Answers3

1

In general you cannot know what headers are transitively included by the headers you include, and any standard header is allowed to, but not required to, include any other header. And you shouldn't rely on transitive includes ever. You should include the headers you need for the things that you use and then you'll be good.

Jesper Juhl
  • 30,449
  • 3
  • 47
  • 70
  • still, the sentece "Some compilers on some platforms may on some time of the month compile even though you failed to include the header" I am not capable of. Why it this possible? Because of the headers included. So I do rely on "transitive" includes, since they decide whether i compile successfuly or not – milanHrabos Jun 28 '20 at 19:48
  • @milanHrabos It's perfectly valid for a compiler to include *all* of the standard library for all of your source files whenever you compile something. Doing so would usually be a very stupid and slow thing, but still valid. That doesn't mean you can rely on such behaviour though. You should include what you use if you want deterministic behaviour. – Jesper Juhl Jun 28 '20 at 19:52
  • This is rather recommendation then answer. Even if compiler can include *all* libraries or headers, it does not - because it decides upon something (i.e. what to include) and I would like to know, how does compiler "decides" what to actually include and what headers are in the end important – milanHrabos Jun 28 '20 at 19:55
  • @milanHrabos `#include` is basically cut'n'paste - *also* for the standard library headers. How a given standard library implementation has chosen to organise their header files and which happen to include which others is an *implementation detail*. That can (and will) vary from implementation to implementation, but you shouldn't need to care, since if you just include the correct headers things will work. If you don't; all bets are off. – Jesper Juhl Jun 28 '20 at 20:00
  • see my edits. I do care. It could be determine from the stdlib source. How? – milanHrabos Jun 28 '20 at 20:12
  • @milan "see my edits. I do care. It could be determine from the stdlib source. How?" - I cannot parse that at all. I have no idea what you are trying to say. Sorry. – Jesper Juhl Jun 28 '20 at 20:14
0

<iostream> is calling <string>

Do you mean that it includes <string>? Calling is something that is done to functions.

But I do not see any includes of <string> in Standard library header <iostream> from c++ standard: https://en.cppreference.com/w/cpp/header/iostream.

What you're reading is documentation of <iostream>. Indeed, <iostream> is not documented to include <string>.

So this code works (file foo.cpp):

It may work with some standard library implementation. It may not work using other implementations.

  1. (so should I trust that documentation, when the did not mentioned <string> header in "Includes" list of <iostream>?).

cppreference is fairly high quality. Unless it contradicts the standard, it is fairly safe to assume that it is correct. Indeed in this regard it is correct: <iostream> is not guaranteed to include <string>.

  1. what calls what?

Some headers include some other headers. There is no need to know more accurately than that because you should not rely on transitive inclusions (except those that are documented).

And what is the "true" header, that define std::string of them?

As per documentation, std::string is defined in header named string (commonly stylised as <string> which matches the conventional inclusion syntax).

so how's possible for a compiler to compile only sometimes?

It could ask the current time from the operating system and use a branch to do one thing or another depending on that time. Compilers don't typically do that, but the point is that they could.

More realistically, you may at some point need to compile your program using another (version) of the compiler (or standard library implementation). Different implementations behave different from one another.

Which of these headers are really important for successful compilation?

The ones that are documented to define and declare the names whose definitions and declarations your program relies on. If you use std::string, then you must include the header that defines std::string which is <string>.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • so how can i resolve whether my specific implmenation of stdlib++ does include in ? when you said `Different implementations behave different from one another`, how can I determine from the source of my stdlib, that it does that inclusion? – milanHrabos Jun 28 '20 at 20:04
  • @milanHrabos You've actually already determined that. If the program that you show in the question compiles, then that implementation of standard library does transitively include `` in ``. Note that there isn't much useful that can be gained from knowing this. – eerorika Jun 28 '20 at 20:06
  • @milanHrabos If you need stuff from both `iostream` and `string` you should simply `#include` both and not rely on one possibility including the other. – Jesper Juhl Jun 28 '20 at 20:07
  • @eerorika, no. I do not want this approach of "If it compiles...". I want to determine it *before* I try to compile. From source of my stdlib (which you mentioned, there is a branch for that) – milanHrabos Jun 28 '20 at 20:07
  • 1
    @milanHrabos You can do this: read the header ``. If it defines `std::string`, then you know "yes, `` of this (version of) standard library implementation defines `std::string`". If not, then read all files that `` includes. Do this recursively to all included files. If any of them define `std::string`, then you know "yes, ...". If none of them define `std::string`, then you know "no, `` of this (version of) standard library implementation does not define `std::string`. I'll mention again just in case: Knowing the answer is not useful. – eerorika Jun 28 '20 at 20:11
0

You should always check the documentation for any symbol you use and include any headers it is specified to require.

The C++ standard only specifies which symbols must be made available when a standard header is included. It does not place any limits on what other symbols are made available. In your example, the standard specifies the <iostream> must include <ios>, <streambuf>, <istream>, and <ostream>, but <iostream> may include any other headers its authors want. It may also forward-declare any symbols it may need.

  1. (so should I trust that documentation, when the did not mentioned <string> header in "Includes" list of <iostream>?).

You should trust that the symbols specified as being available when you include <string> will be. That is all. You may not assume that those symbols will not be visible when including any other header.

  1. what calls what? And what is the "true" header, that define std::string of them? (is it /usr/include/c++/8/bits/basic_string.h?...)

This is an implementation detail that can only be answered by inspecting the implementation's headers. Libstdc++ (the standard library implementation used by GCC) has the declaration of the std::string class in bit/stringfwd.h and its definition in bits/basic_string.h and bits/basic_string.tcc (for the current version, at least), but that is not required at all. If the libstdc++ maintainers decided they wanted to refactor and reorganize things, they would be free to do so. The only requirement that is guaranteed by the C++ language is that std::string must be available when <string> is included.

But from the upper output of the "string headers", there is multiple of them, so how's possible for a compiler to compile only sometimes?

Different standard library implementations or different versions of the same implementation could transitively include different headers. Different compiler flags (i.e. a debug flag or different standard compliance mode) could transitively include different headers.

Which of these headers are really important for successful compilation?

  1. How to orient in cpp headers, which are meaningful for compiler, and could be tracked their "#include stack" (i.e. other meaningful headers)?

All of them are meaningful. The standard library's authors wouldn't include a header if they didn't need it for something. Just because you aren't using any symbols declared/defined in that header directly doesn't mean none are being used.


EDIT: If it depends on my specific implementation of my stdlib++, then I want to know how can I determine from source whether that inclusion is made before I try to compile. Not by "If it compiles, then it works".

The only way to know is to look at your standard library implementation's headers. There is nothing magical about them; they're just C++ code. If you want to know if <iostream> includes a declaration or definition of std::string, open your implementation's copy of <iostream> and look for a declaration or definition of std::string. Repeat this process for any headers that <iostream> includes.

Miles Budnek
  • 28,216
  • 2
  • 35
  • 52
  • What is the difference between `*.h` header and `*.tcc` header? In one is delcaration and the other definition? – milanHrabos Jun 29 '20 at 07:24
  • Also, from your last note `open your implementation's copy of `, that's the think - as you mentioned, `std::string class in bit/stringfwd.h and its definition in bits/basic_string.h and bits/basic_string.tcc`, so there is *multiple* files for finding the implementation, so I cannot open `` since I do not know what file it is, and in what directory I can find it in my linux. Being this a `c` header, I would probably look at `/usr/include` but since it is c++ and moreover separated in *multiple* files, I really have no idea where to look for the implementation – milanHrabos Jun 29 '20 at 07:30
  • .................................................................. – milanHrabos Jun 29 '20 at 13:31
  • @milanHrabos The `.tcc` (`.tpp` and `.icc` are also common) extension is often used for files containing out-of-line template definitions. See https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file. – Miles Budnek Jun 29 '20 at 16:42
  • @milanHrabos `iostream` is a single file. You can find it somewhere in your compiler's include search path (for instance, for GCC do `g++ -v /dev/null -o /dev/null` to get it to list its default search path); in fact the `cc -H` output from your question tells you exactly where it is: `/usr/include/c++/8/iostream`. From there you just follow the `#include` directives to find other files it includes until you find what you're looking for. Same as reading _any_ C++ code. Again, the standard library isn't magic; it's just C++ code. – Miles Budnek Jun 29 '20 at 16:44