Where to put compile-time-constant arrays?

2.5k views Asked by At

Say I have an array storing the first 10 primes, like this:

const int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};

This is all very fine and simple as long as I have 1 .cpp file. However, if I have multiple .cpp files I don't really know where to put this array.

An obvious solution would be this:

// primes.h:
extern const int primes[10];

// primes.cpp:
extern const int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};

However, the problem with this is that the primes array is no longer a compile time constant. Say x.cpp wants to do some heavy calculations involving primes[k], with k a compile time constant, it would have to do an actual memory look-up. I don't like that.

So where do I put this array so that:

  1. It's only once in the binary (not once per .cpp file)
  2. array[SOME_CONSTANT] is also a compile-time constant

Edit

how about this?

inline int prime(int i) {
    static const int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
    return primes[i];
}

PS: Even the "obvious solution" above took me quite some time to write. Apparently const variables have internal linking by default, so I had to add "extern" to the primes.cpp file to make it work.

3

There are 3 answers

9
Ben Voigt On BEST ANSWER

I think this should work (now updated after Migi's testing revealed a flaw):

template <bool dummy>
struct primes_lut
{
    static const int values[];
};

template<bool dummy>
const int primes_lut<dummy>::values[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 };

static auto& primes = primes_lut<true>::values;

(There is no problem in C++ that cannot be solved by use of more templates.)

Another approach:

struct primes_lut { int values[10]; };
inline const primes_lut& primes_lut_provider(void)
{
    static const primes_lut values = { {2, 3, 5, 7, 11, 13, 17, 19, 23, 29} };
    return values;
}
static const int (&primes)[10] = primes_lut_provider().values;

Finally, none of these tricks are necessary with a modern linker than implements constant folding.

4
Damon On

You could use enum inside a header. Enums are guaranteed to be compile time constants and (unless you use C++0X enum class) implicitly convert to integers.

0
Marian Spanik On
static const int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};

in a header file. This may lead to a bigger executable (each source file will have its own copy of the array) but I think the same problem applies for the currently accepted answer.