Suppose that I have two template functions declared in a header file:
template <typename T> void func1(const T& value);
template <typename T> void func2(const T& value);
And suppose that the implementation of these functions (also in a header file and not in a source file, because they are templates) uses some implementation helper function, which is also a template:
template <typename T> void helper(const T& value) {
// ...
}
template <typename T> void func1(const T& value) {
// ...
helper(value);
}
template <typename T> void func2(const T& value) {
// ...
helper(value);
}
In any source file that I include the header file, the helper function will be visible. I don't want that, because the helper function is just an implementation detail. Is there a way to hide the helper function?
A common approach (as used in many Boost libraries, for example) is to put the helper in a namespace called details
, possibly in a separate header (included from the "public" header).
There's no way to prevent it from being visible, and callable, but this quite clearly indicates that it is part of the implementation, not the interface.
The established precedent is to put that sort of thing in a specially (i.e. consistently) named nested namespace. Boost uses namespace details
, Loki uses namespace Private
. Obviously nothing can prevent anyone from using the contents of those namespaces, but both names convey the meaning that their contents aren't intended for general consumption.
That being said, an easy alternative is to turn func1
and func2
from free function templates into static member function templates of some common class; this way, helper
can simply be a private member of said class, invisible to the outside world:
struct funcs {
template<typename T>
static void func1(T const& value) {
// ...
helper(value);
}
template<typename T>
static void func2(T const& value) {
// ...
helper(value);
}
private:
template<typename T>
static void helper(T const& value) {
// ...
}
};
Two options off the top of my head:
Since the user of your code needs to see the full definition of the func1
function, its implementation, nor its helper function implementation, cannot be hidden.
But if you move the implementation into another file, the user will only have to be confronted with the template declaration:
//templates.h
template< typename T > void f1( T& );
#include <templates_impl.h> // post-inclusion
And the definition:
// templates_impl.h
template< typename T > void f1_helper( T& ) {
}
template< typename T > void f1( T& ) {
// the function body
}
In C++20 you can now use modules.
For this you could create a module some_module.cppm
holding all functions and marking only the interface (either the individual functions or a namespace) with export
while not exposing the helper functions:
// some_module.cppm
export module some_module;
template <typename T>
void helper(const T& value) {
// ...
}
export
template <typename T>
void func1(const T& value) {
// ...
helper(value);
}
export
template <typename T>
void func2(const T& value) {
// ...
helper(value);
}
In the case above only the functions func1
and func2
are exported and can be accessed inside main.cpp
:
// main.cpp
#include <cstdlib>
import some_module;
int main() {
func1(1.0);
func2(2.0);
return EXIT_SUCCESS;
}
In clang++12
you can compile this code with the following three commands:
clang++ -std=c++2b -fmodules-ts --precompile some_module.cppm -o some_module.pcm
clang++ -std=c++2b -fmodules-ts -c some_module.pcm -o some_module.o
clang++ -std=c++2b -fmodules-ts -fprebuilt-module-path=. some_module.o main.cpp -o main
./main
I would (as said before) make a template class, make all functions static and the helper function private. But besides that I'd also recommend making the constructor private as shown below:
template <typename T>
class Foo{
public:
static void func1(const T& value);
static void func2(const T& value);
private:
Foo();
static void helper(const T& value);
}
When you make the constructor private, the compiler won't allow instances of this template class. So the code below would become illegal:
#include "foo.h"
int main(){
int number = 0;
Foo<int>::func1(number); //allowed
Foo<int>::func2(number); //allowed
Foo<int>::helper(number); //not allowed, because it's private
Foo<int> foo_instance; //not allowed, because it's private
}
So why would someone want this? Because having different instances that are EXACTLY the same is something you probably never want. When the compiler tells you that the constructor of some class is private, then you can assume that having different instances of it would be unnecesarry.
I know you mean that you want to hide it so finely that callers have no way to find your helper functions as long as they don't change your code file. I know it so well because I have very similar needs recently.
So how about wrapping your helper functions in an anonymous namespace? This is recently the most elegant style I found:
namespace YourModule
{
namespace
{//Your helper functions}
//Your public functions
}
This practice effectively hides your internal functions from the outside. I can't find any way that a caller can access functions in anonymous namespaces.
It's usually not a good practice, as answered by @user3635700 , to convert your namespace to a class full of static functions, especially when you have templates of static variables like:
template <uint8_t TimerCode>
static uint16_t MillisecondsElapsed;
If this variable appears in a class, you'll have to initialize it somewhere outside the class! However, you can't do it because it's a template! WTF!
It seems that an anonymous namespace in the header file, which is criticized by some, is the only and the most perfect solution to our needs.
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