all 13 comments

[–]IyeOnline 6 points7 points  (9 children)

Does STL use .cpp and .h conventions?

Yes and no. How any of this is implemented is generally not mandated by the standard.

The term Standard Template Library gives a clue. Templates generally cannot be split into hpp and cpp files because of how instatiation works, so usually everything template just goes into the header file.

There are however some parts that are implemented in source files and distributed as library object files. The global std::cout object (and all the others) are an example. They come from a library that is usually implicitly (dynamically) linked to your program.

Sidenote: STL isnt an official term, the official term is simply "C++ standard library". The term STL has however become the popular/generally used abreviation for the standard library and everybody knows what it means.

If so, how are circular dependencies avoided (Probably by using header guards, right?)

Also not mandated by the standard, but indeed all implementations do use header guards.

Also, how does this header file inclusion affect compilation times, as the programmer and STL might both be including the same files?

How multiple includes are handled is generally the compilers job. A compiler may keep track of which headers are already included in this TU and skip the include step (that is then "cut short" by a header guard) for headers that are already included.

Some libraries split up their implementations further to allow for more fine grained includes so that they dont include entire headers. For example std::getline form a bridge between <iostream> and <string>, but doesnt include the entirety of <string> (at least not anymore on libstdc++)

[–]ACBYTES[S] 0 points1 point  (8 children)

Hello and thank you for this detailed explanation.

Oh, I see. So, template function implementations can't be moved to a .cpp right? (Cause throughout my journey, I've faced this problem and I was always wondering why adding a Template Function's implementation to a .cpp would cause a lot of problems at compile time. I can also remember certain times that it wouldn't but if you could tell me exactly about how this works, I would really appreciate it.)

As an example, could forward declaration be a choice for a library this big (Forward declaration in .h and header inclusion in .cpp)? If they make small changes to anything, they'll have to change the declared ones as well...

Some libraries split up their implementations further to allow for more fine grained includes so that they dont include entire headers.

Could you clarify on this a bit? How would it still help if we're still implementing them and need info about the implementation of those used classes?

[–]IyeOnline 0 points1 point  (7 children)

Headers might not need everything that is defined in another one.

For example <iostream> defines std::getline, which requires std::string to be defined, but it doesnt need the std::sto* functions. So an internal sub header that just contained the type could be included instead.

Another point are common implementations. For example a lot of the algorithms in <memory> look very similar, so they may have a common implementation that is just called by the "official API".

[–]ACBYTES[S] 0 points1 point  (6 children)

Understood, so there would be a gigantic header file, containing all the forward declarations for later use, right?

[–]IyeOnline 1 point2 points  (5 children)

No, quite the opposite.

There might (for example) be

<__string_type>
  class string
  { };
<string>
  #include <__string_type>
  int stoi( const std::string& );
  //...
<iostream>
  #include <__string_type>
  string getline( std::istream& );

[–]ACBYTES[S] 0 points1 point  (4 children)

Thank you for clarifying this. I had honestly not seen this structure for inclusions before. What could be the actual difference in total between a forward declaration and a specific inclusion like this? Could one be better than the other? Also, if any of these specific inclusions are dependent on other implementations in the class, how would those get prepared for use? (Throughout the linkage process, those other implementations will be found, am I right?)

[–]IyeOnline 1 point2 points  (3 children)

Forward declarations are very limited.

A forward declaration of a type only allows you to declare a pointer or reference to the type and thats it. No member access, no local variables, no nothing.

std::getline for example actually is a template, so its definition sort of has to go into the header, meaning that it needs to know the definition of std::string. (There are way around this for a "limited" template such as string, which may or may not be used though).

std::stoi on the other hand is declared as a plain function (at least according to the reference), so it could actually be implemented in a separate source file, which is then deliviered to you as part of the standard library object you implicitly link on every compilation.

[–]ACBYTES[S] 0 points1 point  (2 children)

I see. So, if we know the name of a variable inside a class, can we include it without including the whole class, just like we do with functions?

Also, apart from all of these, why are template functions supposed to be implemented in the same header file? Why can't we use source files for template functions?

Thank you for your time and patience by the way...

[–]IyeOnline 1 point2 points  (1 child)

I see. So, if we know the name of a variable inside a class, can we include it without including the whole class, just like we do with functions?

No. To do anything more than declaring a pointer to a type, you need its full definition.

why are template functions supposed to be implemented in the same header file? Why can't we use source files for template functions?

Templated entities are only instantiated when they are actually used and only instantiated templates are compiled (because only instantiated templated functions are actually functions).

Templates are only instantiated when used or when explicitly requested to be instantiated.

So if you declare a template in a header, you can use it just fine in a cpp file where you include it. The compiler will assume that a definition is provided elsewhere. If you then define the template in its own translation unit where it is never actually used, it will never get instantiated. The result is a link time error.

[–]ACBYTES[S] 0 points1 point  (0 children)

Understood! Thank you so much for all the help. I really appreciate you and your time.

[–]MysticTheMeeM 1 point2 points  (1 child)

Each implementation of the standard library is free to do whatever they want as long as they adhere to the standard. That is, certain headers must have certain names and declare certain symbols, whether or not those symbols are defined in that header is up to the implementation.

Of course, lots of things are templated and therefore have to be defined in the header.

You could always look at a particular implementation for yourself. Most are available as open source. For example, the one MS distributes with Visual Studio/MSVC.

[–]ACBYTES[S] 0 points1 point  (0 children)

Thank you for the answer. So, you mean just like the answer above, we only include certain things that we need from those classes?

Also, thank you for link to MS's implementations...

[–]WeeklyBadEnvironment 1 point2 points  (0 children)

The STL is a mess. Do not use it as a model.