Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Define a global variable template?

Usually, we do declare but not define a global variable in the header file. However, we define templates in it. Then the issue arises: is it possible to define a global variable template?

template <uint8_t PinCode>
uint8_t BitMask = digitalPinToBitMask(PinCode);

In reality, a global variable template:

  • instantizes only if at least one compile unit (CU) requires it.
  • causes no redefinition errors if multiple CUs require the same instance.
  • is shared among CUs, i.e., if one CU changes the value of an instance, other CUs requiring the same instance will be affected.
  • calls the initializer only once for each kind of required instance.
like image 336
埃博拉酱 Avatar asked Oct 28 '25 10:10

埃博拉酱


2 Answers

After longer research, I finally found the most elegant solution. The definition style depends on whether you want to initialize the variable.

If the variable does not need initialization, you only need a header file:

template <int TimerCode>
int TCCRB;

Yes, it is and must be so simple. Don't add "static" or "extern" keywords like we usually do for variables in a header file. It will pass compilation and work as a global variable template among all CUs. Same instances will share the same actual variable, i.e., changes in one CU will affect other CUs, as long as they have the same template arguments.

As we know, if you define a variable with no necessary keywords like "static" or "extern" in a header file, it will cause a redefinition error if the header is included in more than one CUs. "static" tell the compiler to copy this variable for each CU as individual variables, so changes in one CU won't affect that in another CU. Instead, "extern" tells the compiler that this variable here is only a declaration. It's defined and owned in only one of the CUs, and other CUs should only keep a reference or symbol to it. So that changes in one CU WILL affect other CUs.

However, a variable template is neither a static definition nor an extern declaration. It's a special instruction to the compiler: find all cases of references to this template, combine those of the same template arguments, and generate one definition automatically for each unique instance! This time the compiler takes the responsibility to avoid redefinition: it scans all CUs and then generates unique definitions itself!

This automatic definition is so convenient if you don't want to give the variable an initial value, and if there are too many possible instances to be listed one by one. However, if you do want an initial value, you'll have to define it yourself, and you'll need an individual CU to own these variables to avoid redefinition:

//In the header file:
template <int TimerCode>
extern int TCCRA;
//In the CPP file:
template <>
int TCCRA<1> = 2;
template <>
int TCCRA<2> = 5;
//Naturally you have to provide initial values for all possible instances …

For this case, the "extern" keyword is necessary because you explicitly defined all valid instances in your specially provided CU, and other CUs must refer to this definition. The compiler shouldn't generate a random definition itself. This is very much like a normal global variable definition, only adding some template grammars. However, the user can only use instances provided in your CPP file. This is also very natural because only for known instances can you provide an initial value.

I found very few tutorials on this topic on the Internet. I hope my experience will help more people ~

like image 175
埃博拉酱 Avatar answered Oct 31 '25 00:10

埃博拉酱


The standard defines many global constants which are templatized such as the type traits type_trait_v constants.

They are defined as such in the header

template<class T>
inline constexpr some_type some_variable = ...;

In your example you could do something like

template<uint8_t Pin>
inline constexpr uint8_t BitMask = digitalPinToMask(Pin);

For this to work then digitalPinToMask must be invocable in a constexpr context.

like image 34
Mestkon Avatar answered Oct 31 '25 01:10

Mestkon