0

I am trying to write my first (very) small, for now only self-use, library. In the process I came across questions regarding how I should separate my headers/source code/object files in a logical way.

To be more specific, I'm writing a small templated container class, so for one I have to include the implementation of this class inside its header.

I have a directory structure like this:

include/ - "public" .hh header files included by extern projects
src/ - .cc files for implementation (+ "private" .hh header files?)
lib/ - .o compiled library files linked by extern projects

I am already not sure if this makes sense.. in my case I also wrote some helper-classes used by my templated container class, one of which is something like an iterator. So I have the following files:

container.hh
container.cc
container_helper.hh
container_helper.cc
container_iterator.cc
container_iterator.hh

While I want to have access to their functions in external projects (e.g. incrementing the iterator), it makes no sense to me that a project would specifically

#include "container_iterator.hh"

Now, since I want projects to be able to use the container class, I put "container.hh" and "container.cc" (since it must be included in "container.hh" because of the template) into the "include/" directory, which is then included by other projects. Now my confusion arises.. the container class needs access to the helper classes, but I don't want other projects to only include the helper classes, so it seems wrong to place also the helper classes into "include/" directory. Instead, I would place them in "src/". But if I do this, then to include these in "include/container.cc" I have to use relative filepath

#include "../src/container_iterator.hh"

But now if I "distribute" my library to an external project, i.e. I only make the "include/" directory visible to the compiler, it will not compile (?), since "../src/container_iterator.hh" does not exist. Or do I compile the container class and put it as library into "lib/", which is then linked by other projects? But even then do I not still need to include the header "container.hh", to be able to find the function declarations, which leads to the same problem?

Basically I'm lost here.. how does the standard do this? E.g. I can

#include <vector>

, but I don't know of any header to only include std::vector::iterator, which would make no sense to do so.

At some point in my expanation I must be talking nonsense but I cannot find where. I think I understand what a header and a library is/should be, but when it comes to how to design and/or "distribute" them for an actual project, I am stuck. I keep coming across problems like this even when I started learning C++ (or any language for that matter), no course / no book ever seems to explain how to implement all these concepts, only how to use them when they already exist..

Edit

To clarify my confusion (?) more.. (this got a bit too long for a comment) I did read before to put implementation of templated classes into the header, which is why I realized I need to at least put the "container.cc" into the include/ dir. While I don't particularly like this, at least it should be clear to an external user to not include ".cc" files.

Should I take this also as meaning that it never makes sense to compile templated classes into a library, since all of it will be always included? (So templated code is always open-source? ..that sounds wrong?)

And in this case I still wonder how STL does it, does vector declare & define its iterator in its own header? Or is there a separate header for vector::iterator I could include, it just would make no sense to do so?


Hopefully I explained my intent clearly, please comment if not. Thanks for any help!

Shiwayari
  • 315
  • 3
  • 12
  • Not an exact duplicate but very relevant: https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file – Richard Critten Jul 07 '18 at 13:52
  • 1
    " I'm writing a small templated container class," - template implementations need to be in header files, and normally in "publicly" accessible ones - C++ doesn't really have a concept of "private" code files. You seem to be over-thinking this. –  Jul 07 '18 at 13:52
  • @NeilButterworth thanks for the comment, I edited my question to try and clarify more (too long for comment) – Shiwayari Jul 07 '18 at 14:22
  • "So templated code is always open-source? " - open source is about what license you use, not about code visibility. –  Jul 07 '18 at 14:25
  • Re edit - it's quite common to have public `xxx.h` files that include `xxx.imp` (implementaion) files. This is a common method used to separate the public interface and implementation details. I suggest you do not use the `.cc` extension for files that are going to be `#included`. – Richard Critten Jul 07 '18 at 14:39

1 Answers1

1

In my experience, the most common method to handle your problems is to have headers with the template declarations and documentation (your .hh files), which also include .inc or .tcc (your preference) files with the template definitions. I also suggest keeping all files that may be included by external projects in the same folder, but if you want to keep things clean, put your .inc/.tcc files in a folder within include called detail (or bits if you like GNU style). Putting stuff in a detail folder, and using a weird extension should deter users enough.

To answer your other questions: Due to the nature of C++ templates, either the entire source of the parts of a template you use must be present in the translation unit (ie. #include'd), or you can use explicit instantiation for a finite number of arguments (this is not generally useful for a container, though). So, for most purposes, you have to distribute a template's source, though, of course, (as mentioned in the comments) "open source" is about licence, not source visibility.

As for the standard libraries, lets use <vector> as an example. The GNU C++ Library has a vector file that (among other things) includes bits/stl_vector.h which has the declarations & documentation, and includes a bits/vector.tcc that has the definitions. LLVM's libc++ just has one giant file, but puts the declarations at the top (without documentation!) and all the definitions at the bottom.

As a final note, there are lots of open source C++ libraries that you can take a look at for inspiration in the future!

golvok
  • 1,015
  • 12
  • 25