Eine lookup table LUT fest im Programm compilieren sollte mit C++ und constexpr kein Problem sein. Zur Kontrolle ob es funktioniert der erzeugte Assembler Code
Beispiel 1 nutzt std::array da es zur Compilezeit eine bekannte Länge hat und eine normale ausgeschriebene Schleife. Unschön ist, dass das Array erst deklariert und danach erst initialisiert wird. Also kein RAII. Zusätzlich muss von Hand der return Type der Funktion f bestimmt werden. Auf jeden Fall funktioniert es. Im Assembercode sind die vorraus berechneten Konstanten zu sehen, die einfach in das Array kopiert werden.
template<size_t N, typename Function> constexpr auto makeLookUpTable(Function f) { using T = std::invoke_result_t<Function,size_t>; std::array<T,N> arr{}; for(size_t i=0; i < N; ++i) { arr[i] = f(i); } return arr; } auto func() { auto f = [](size_t i){ return std::sin(i/4.0*M_PI); }; constexpr auto arr = makeLookUpTable<4>(f); return arr; }
func(): movq %rdi, %rax movq $0x000000000, (%rdi) movq .LC1(%rip), %rdx movq %rdx, 8(%rdi) movq .LC2(%rip), %rcx movq %rcx, 16(%rdi) movq .LC3(%rip), %rsi movq %rsi, 24(%rdi) ret .LC1: .long 1719614412 .long 1072079006 .LC2: .long 0 .long 1072693248 .LC3: .long 1719614413 .long 1072079006
Die nächste Beispiel nutzt fold expressions und keine explizite Schleife mehr. Damit ist auch RAII wieder Möglich. Der erzeugte Assemblercode ist identisch, da ja auch das selbe gemacht wird. Nur die Syntax ändert sich ein wenig. Was gibt es noch zu sagen? Eigentlich nichts. Ich frage mich wie viel Konstanten erzeugt werden können, bevor die Binary platz.
template<size_t N, typename Function> constexpr auto makeLookUpTable2(Function f) { auto impl = [&f]<std::size_t... Ints>(std::index_sequence<Ints...>) { return std::array{(f(Ints))...}; }; return impl(std::make_index_sequence<N>{}); } auto func2() { auto f = [](size_t i){ return std::sin(i/4.0*M_PI); }; constexpr auto arr = makeLookUpTable2<4>(f); return arr; }
func2(): movq %rdi, %rax movq $0x000000000, (%rdi) movq .LC1(%rip), %rdx movq %rdx, 8(%rdi) movq .LC2(%rip), %rcx movq %rcx, 16(%rdi) movq .LC3(%rip), %rsi movq %rsi, 24(%rdi) ret .LC1: .long 1719614412 .long 1072079006 .LC2: .long 0 .long 1072693248 .LC3: .long 1719614413 .long 1072079006