In a project I am working on, I am currently implementing an algorithm which is templated. I had some problems organizing my function declarations and definitions, because templates are involved (I asked a question here about how to deal with non-templated functions "grouped" together with the templated ones). This, however, made me wonder about a general proper organization of such files.
I wanted to separate all the definitions from all the declarations (just for readability purposes, even if I had to include templated definitions back into declarations).
The answers I got suggested organization such as this:
algo.h
for all the function declarationsalgo.tpp
which will be included in algo.h
(templates need declarations at compile time)algo.cpp
not included anywhere.This works well if all the defined functions are supposed to be visible to the end-user (i.e. all the declarations are in the algo.h
file). However, sometimes I like to break my big functions into smaller functionalities, but I would like the end-user to be able to access only the "big function" and not their sub-parts. In a non-templated set-up, I would do this in this way:
algo.h
would contain only the declarations meant for the end-user (which will become accessible through the include)algo.cpp
algo.cpp
, allowing my big function in algo.cpp
(the one declared in algo.h
) to use them, but not making them accessible to the end-user.This does not work any more if those sub-functionalities are not themselves templated, but are used by the templated function. The templated sub-functionalities can go into the .tpp
file, get used by the templated "big function", and everything is good.
However, if those functionalities are non-templated, they would cause a multiple definitions error (which is what my previous question was about) if placed in the .tpp
file. On the other hand, if they are in the separate .cpp
file, they either become accessible to the end-user (if I put the declarations in the .h
file), or become inaccessible to the big function meant to use them (if I do not put the declarations outside the .cpp
file).
What is the proper way of organizing functions, some templated and some not, some of which are supposed to be accessible to the end-user, and some not, into multiple files?
Ideally, (for completeness), the answer I'm looking for would address the placement of the following (in the .h
, .tpp
, .cpp
, or other appropriate files):
Short almost-pseudo-code example of the functionality I want to have (without the file-separation)
// Templated sub-functionality, used by bigFunctionality,
// but ideally not accessible to the end-user
// This might not be possible since it is templated,
// so I am content with putting it in the .tpp file
template <typename Compare>
void subFunctionality(Compare order, .. args ..){ /* impl */ }
// Non-templated sub-functionality, used by
// bigFunctionality, but NOT accessible to the end-user
void moreSubFunctionality(.. args ..) { /* impl */ }
// the main functionality, meant to be
// accessible to everybody across all files:
template <typename Compare>
void bigFunctionality( .. non-templated args ..., Compare order){
subFunctionality(order, .. args ..);
moreSubFun(.. args ..);
// more stuff
}
Once again, I am looking how to separate this in to multiple files (even if they are included in each other, as it has to be done with templates), partially for readability purposes and partially for accessibility.
Just for clarifications, these are algorithms --> functions, and not classes. (I know that putting templated and non-templated functions in to the same templated class would solve my problems).
PS: I know the title of the question is very big and long, so if somebody has an idea about shortening it, I would be more than happy for the suggestions/edits
This is an unfortunate side-effect of the absence of modules in C++: what is declared is necessarily visible.
In general, the guideline is to simply use a "private" namespace (nested within the user-visible namespace(s)):
internal
).tpp
fileThen, you document that this namespace is internal and non-suitable for client callers. If possible, you also annotate the namespace/functions so that no documentation is generated for them.
At this point, those functions are clearly private and hidden.
If you wish to go one step further, you may simply declare them private
in a class
(*), and then have only your functions be friend
of this class. Then, any attempt to use them will result in the compiler emitting an error: they are visible, but not accessible. However, most people (starting with Boost developers) just do not bother, and I certainly do not either.
(*) The class
essentially replaces the private namespace.
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