I have a template struct Distance
that uses constexpr unsigned char mm2cm = 10
Since Distance
is a template class, I must define mm2cm
and Distance
in a header file.
This header file is included by cpp files.
I want mm2cm
to only be visible in this header file and not in the cpp files that include this header, ie:
Distance.hpp
constexpr unsigned char mm2cm = 10;
template <int offset>
struct Distance{
int mm;
int convToCm() const { return offset + mm2cm * mm; }
};
Main.cpp
#include "Distance.hpp"
#include <iostream>
int main(){
//I do not want to be able to use mm2mm outside Distance.hpp, as follows
std::cout << (int)mm2cm << std::endl;
}
One way I could solve this is using #define mm2cm 10
and #undef mm2cm
at the beggining and end of the header file (instead of constexpr unsigned char mm2cm = 10
.
However, a lot of people discourage the use of macros for reasons. This post lists some reasons why), and this website states that:
In general, the const keyword is preferred for defining constants and should be used instead of #define.
Another way I could solve this is by making mm2cmm
a private static member of Distance
.
However, in the actual, larger problem I am trying to solve, I have multiple variables that I only want to be visible in this header file, and making all of them private static members will make my class look ugly (in other words, there must be a better way than this solution).
I would be most grateful if someone could provide me the most optimal way to ensure mm2cm
is only visible to Distance
or only visible within this header file.
A prior edition of this post used a type template parameter. This has been changed to a non-type template parameter since the actual problem I am trying to solve uses a non-type template parameter.
Reviewing your requirements, this is the best I could come up with...
template <int offset>
struct Distance {
private:
enum Constants : unsigned char {
mm2cm = 10,
};
public:
int mm;
int convToCm() const { return offset + mm2cm * mm; }
};
It hides the value in an enum, and can be used with other constants.
convToCm()
looks like it is the wrong way (looks like it converts cm to mm.)
If mm2cm was an object or function, then it would inhibit the compiler's ability to optimize. We could do a base class implementation, but that would still have the "ugly" multiple private / static members.
The use of integer offset as a template is awkward for the compiler.
Distance<10> value;
Distance<12> value2;
Requires the compiler to generate
int Distance<10>::convToCm() const;
int Distance<12>::convToCm() const;
Both of which have identical code except for the template parameter 10/12. This would be more problematic if the objects were in a container, where std::vector< Distance<10> >
requires different code to std::vector< Distance<12> >