Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
Template metaprogramming
(section)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
== Static Table Generation == The benefit of static tables is the replacement of "expensive" calculations with a simple array indexing operation (for examples, see [[lookup table]]). In C++, there exists more than one way to generate a static table at compile time. The following listing shows an example of creating a very simple table by using recursive structs and [[variadic templates]]. The table has a size of ten. Each value is the square of the index. <syntaxhighlight lang="cpp"> #include <iostream> #include <array> constexpr int TABLE_SIZE = 10; /** * Variadic template for a recursive helper struct. */ template<int INDEX = 0, int ...D> struct Helper : Helper<INDEX + 1, D..., INDEX * INDEX> { }; /** * Specialization of the template to end the recursion when the table size reaches TABLE_SIZE. */ template<int ...D> struct Helper<TABLE_SIZE, D...> { static constexpr std::array<int, TABLE_SIZE> table = { D... }; }; constexpr std::array<int, TABLE_SIZE> table = Helper<>::table; enum { FOUR = table[2] // compile time use }; int main() { for (int i=0; i < TABLE_SIZE; i++) { std::cout << table[i] << std::endl; // run time use } std::cout << "FOUR: " << FOUR << std::endl; } </syntaxhighlight> The idea behind this is that the struct Helper recursively inherits from a struct with one more template argument (in this example calculated as INDEX * INDEX) until the specialization of the template ends the recursion at a size of 10 elements. The specialization simply uses the variable argument list as elements for the array. The compiler will produce code similar to the following (taken from clang called with -Xclang -ast-print -fsyntax-only). <syntaxhighlight lang="cpp"> template <int INDEX = 0, int ...D> struct Helper : Helper<INDEX + 1, D..., INDEX * INDEX> { }; template<> struct Helper<0, <>> : Helper<0 + 1, 0 * 0> { }; template<> struct Helper<1, <0>> : Helper<1 + 1, 0, 1 * 1> { }; template<> struct Helper<2, <0, 1>> : Helper<2 + 1, 0, 1, 2 * 2> { }; template<> struct Helper<3, <0, 1, 4>> : Helper<3 + 1, 0, 1, 4, 3 * 3> { }; template<> struct Helper<4, <0, 1, 4, 9>> : Helper<4 + 1, 0, 1, 4, 9, 4 * 4> { }; template<> struct Helper<5, <0, 1, 4, 9, 16>> : Helper<5 + 1, 0, 1, 4, 9, 16, 5 * 5> { }; template<> struct Helper<6, <0, 1, 4, 9, 16, 25>> : Helper<6 + 1, 0, 1, 4, 9, 16, 25, 6 * 6> { }; template<> struct Helper<7, <0, 1, 4, 9, 16, 25, 36>> : Helper<7 + 1, 0, 1, 4, 9, 16, 25, 36, 7 * 7> { }; template<> struct Helper<8, <0, 1, 4, 9, 16, 25, 36, 49>> : Helper<8 + 1, 0, 1, 4, 9, 16, 25, 36, 49, 8 * 8> { }; template<> struct Helper<9, <0, 1, 4, 9, 16, 25, 36, 49, 64>> : Helper<9 + 1, 0, 1, 4, 9, 16, 25, 36, 49, 64, 9 * 9> { }; template<> struct Helper<10, <0, 1, 4, 9, 16, 25, 36, 49, 64, 81>> { static constexpr std::array<int, TABLE_SIZE> table = {0, 1, 4, 9, 16, 25, 36, 49, 64, 81}; }; </syntaxhighlight> Since C++17 this can be more readably written as: <syntaxhighlight lang="cpp"> #include <iostream> #include <array> constexpr int TABLE_SIZE = 10; constexpr std::array<int, TABLE_SIZE> table = [] { // OR: constexpr auto table std::array<int, TABLE_SIZE> A = {}; for (unsigned i = 0; i < TABLE_SIZE; i++) { A[i] = i * i; } return A; }(); enum { FOUR = table[2] // compile time use }; int main() { for (int i=0; i < TABLE_SIZE; i++) { std::cout << table[i] << std::endl; // run time use } std::cout << "FOUR: " << FOUR << std::endl; } </syntaxhighlight> To show a more sophisticated example the code in the following listing has been extended to have a helper for value calculation (in preparation for more complicated computations), a table specific offset and a template argument for the type of the table values (e.g. uint8_t, uint16_t, ...). <syntaxhighlight lang="cpp"> #include <iostream> #include <array> constexpr int TABLE_SIZE = 20; constexpr int OFFSET = 12; /** * Template to calculate a single table entry */ template <typename VALUETYPE, VALUETYPE OFFSET, VALUETYPE INDEX> struct ValueHelper { static constexpr VALUETYPE value = OFFSET + INDEX * INDEX; }; /** * Variadic template for a recursive helper struct. */ template<typename VALUETYPE, VALUETYPE OFFSET, int N = 0, VALUETYPE ...D> struct Helper : Helper<VALUETYPE, OFFSET, N+1, D..., ValueHelper<VALUETYPE, OFFSET, N>::value> { }; /** * Specialization of the template to end the recursion when the table size reaches TABLE_SIZE. */ template<typename VALUETYPE, VALUETYPE OFFSET, VALUETYPE ...D> struct Helper<VALUETYPE, OFFSET, TABLE_SIZE, D...> { static constexpr std::array<VALUETYPE, TABLE_SIZE> table = { D... }; }; constexpr std::array<uint16_t, TABLE_SIZE> table = Helper<uint16_t, OFFSET>::table; int main() { for (int i = 0; i < TABLE_SIZE; i++) { std::cout << table[i] << std::endl; } } </syntaxhighlight> Which could be written as follows using C++17: <syntaxhighlight lang="cpp"> #include <iostream> #include <array> constexpr int TABLE_SIZE = 20; constexpr int OFFSET = 12; template<typename VALUETYPE, int OFFSET> constexpr std::array<VALUETYPE, TABLE_SIZE> table = [] { // OR: constexpr auto table std::array<VALUETYPE, TABLE_SIZE> A = {}; for (unsigned i = 0; i < TABLE_SIZE; i++) { A[i] = OFFSET + i * i; } return A; }(); int main() { for (int i = 0; i < TABLE_SIZE; i++) { std::cout << table<uint16_t, OFFSET>[i] << std::endl; } } </syntaxhighlight>
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)