I'm creating a C++ header-only implementation of a library in which I defined multiple constants (defined as static constexpr
s) that I only want to use in the library, to make my code more clear and readable. I thought having internal linkage would be enough to "hide" these constants from any other source files in which I include this library.
However, after including this header in another file where I am writing unit tests for it, I'm getting errors like redefinition of '<constant_name>'
(the test source file has its own constants with the same name since they would be useful in some of the test cases, also defined as static constexpr
s). After some further reading, I now understand that internal linkage means the constants will not be available outside the translation unit, but the translation unit includes the source file as well as any headers it includes. This would explain why I'm getting that redefinition
error, as constants with the same name exist in both the test source file and the library header file, and they end up being a single translation unit.
Currently, I have wrapped said constants in a namespace to avoid the clashing. However, this is not ideal. For example, I still get autocomplete suggestions for these constants in other files when I prefix with the namespace. I would instead like them to be completely hidden.
My question is regarding whether there is any way around this. Is there some way to make these constants truly visible only within the header itself, and invisible to any of the files which include it?
EDIT: Here's some code to demonstrate what I mean.
library.hpp
static constexpr int USEFUL_CONSTANT = 5;
namespace library {
...library implementation here...
}
tests.cpp
#include "library.hpp"
// Constant happens to be useful in tests too, but I don't
// want to expose it for everybody, so I redefine it here
static constexpr int USEFUL_CONSTANT = 5;
...tests here...
I get the redefinition error since both constants would be part of the same translation unit.
A couple of viable approaches:
namespace mylib
{
namespace detail
{
inline constexpr int const goodenough{42};
}
int foo(void)
{
return detail::goodenough;
}
}
private
static
fields of some class with access granted by friend
declarationnamespace mylib
{
int foo(void);
class detail
{
friend int ::mylib::foo(void);
static inline constexpr int const goodenough{42};
};
int foo(void)
{
return detail::goodenough;
}
}
Note: constexpr
implies inline
and const
.