There are many good reasons to have lookup tables computed at compile time. In C++ 14 this is now very easy with generalized constexpr. It took me a while thinking about it before I realised that it really was that easy! Here’s an example of one:
#include <iostream> #include <cmath> //Trivial reimplementation of std::array with the operator[] //methods set to constexpr template<class T, int N> struct array { T elems[N]; constexpr T& operator[](size_t i) { return elems[i]; } constexpr const T& operator[](size_t i) const { return elems[i]; } }; //Function to build the lookup table constexpr array<float, 10> foo() { array<float, 10> a = {}; for(int i=0; i < 10; i++) a[i] = exp(i); return a; } constexpr static array<float, 10> lut = foo<float>(); //This simply serves as a class to be instantiated. template<int I> struct Silly { Silly() { std::cout << "Hello " << I << "\n"; } }; int main() { //Prove they're compile time constants Silly<(int)lut[0]> s0; Silly<(int)lut[1]> s1; Silly<(int)lut[2]> s2; Silly<(int)lut[3]> s3; Silly<(int)lut[4]> s4; Silly<(int)lut[5]> s5; Silly<(int)lut[6]> s6; Silly<(int)lut[7]> s7; Silly<(int)lut[8]> s8; Silly<(int)lut[9]> s9; }
The only minor wrinkle is that std::array does not have its members set to constexpr to a sufficient degree, so it doesn’t work in this context. However, since few features are needed, a minimal reimplementation is pretty straightforward.
Pingback: Enhanced constexpr | Death and the penguin
Pingback: More constexpr in C++20 | Death and the penguin