Search code examples
c++global-variablesheader-filesone-definition-rule

Template trick to define a global array in the header


I came across such a trick:

// This template utilizes the One Definition Rule to create global arrays in a header.
template<typename unused=void>
struct globals_struct
{
   static const uint8 s_str_serialize_flags[256];
   // ...
};
typedef globals_struct<> globals;

template<typename unused>
const uint8 globals_struct<unused>::s_str_serialize_flags[256] =
{
// ... data here ...
};
   // ... and then the array is accessible as:
   uint8 value = globals::s_str_serialize_flags[index])

This code is from Rich Geldreich's Purple JSON that I learnt about from Chad Austin's blog.

Before seeing this code I thought that the only way to have an array in a header-only library is to require the user to #define a magic macro in exactly one file (before including the header).

So I like the template-wrapping trick, but I wonder:

  • is it a C++ idiom (does it have a name)?
  • is it standard-compliant and safe to use?
  • is such a template-wrapping the simplest way to have an array in the header?

Edit: I just came across the same trick in a SO answer where it is shown as an alternative to C++17 inline variables.


Solution

  • For me the simplest is to wrap it into a function (and std::array)

    using arr256 = std::array<std::uint8_t, 256>;
    
    inline constexpr arr256 s_str_serialize_flags() {
        constexpr arr256 values = {/**/};
        return values;
    }
    

    or without the constexpr constraint:

    using arr256 = std::uint8_t[256];
    
    inline const arr256& s_str_serialize_flags() {
        static const arr256 values = {/**/};
        return values;
    }