2017-07-24 15 views
10

Oto fragment, który powinien generować tabelę cosinus przeglądową 2048 elementów, pochodzi z książki budowania systemów wbudowanych przez Changyi Gu:Cosinus lookup stół z C++

#include <cmath> 
#include <array> 

template<typename T> 
constexpr T look_up_table_elem (int i) { 
    return {}; 
} 

template<> 
constexpr uint16_t look_up_table_elem (int i) { 
    return round (cos (static_cast <long double>(i)/2048 * 3.14159/4) * 32767); 
} 


template<typename T, int... N> 
struct lookup_table_expand{}; 

template<typename T, int... N> 
struct lookup_table_expand<T, 1, N...> { 
    static constexpr std::array<T, sizeof...(N) + 1> values = {{ look_up_table_elem<T>(0), N... }}; 
}; 

template<typename T, int L, int... N> 
struct lookup_table_expand<T, L, N...>: lookup_table_expand<T, L-1, look_up_table_elem<T>(L-1), N...> {}; 


template<typename T, int... N> 
constexpr std::array<T, sizeof...(N) + 1> lookup_table_expand<T, 1, N...>::values; 

const std::array<uint16_t, 2048> lookup_table = lookup_table_expand<uint16_t, 2048>::values; 

Uwaga: Napisane dla C++ 11.

Pochodzę ze świata głównie w Javie i mam dobre zrozumienie podstaw języka C++. Ponieważ nigdy naprawdę wyjaśnione w książce, jestem naprawdę mylić, jak to urywek osiągnąć zadanie, i jak to osiągnąć następujące (także wyjęte z książki):

specjalizację szablonu i klasy dziedziczenie pomoże nam pozbyć się restrykcji, że funkcja constexpr może mieć tylko stan powrotu jako jej ciało funkcyjne, dlatego tablica przeglądowa musi zostać wypełniona ręcznie, gdy zwiększa się rozmiar tabeli.

Każda pomoc zostanie bardzo doceniona. Rozumiem część z szablonem constexpr, która wygenerowałaby rzeczywistą wartość, ale nie jestem naprawdę pewien, co robi struktura i jak budowana jest ostateczna tablica.

Odpowiedz

8

Na pierwszy rzućmy okiem na następujące linii:

const std::array<uint16_t, 2048> lookup_table = 
     lookup_table_expand<uint16_t, 2048>::values; 

Tam lookup_table zostanie kopia wykonana z values tablicy odbyło się wewnątrz struktury lookup_table_expand<uint16_t, 2048>. To jest proste, zobaczmy teraz, co się stanie, gdy tworzenie instancji szablonu zostanie wykonane.

Mamy podstawowy szablon z pustego korpusu (gdzie deklaracja naprzód byłoby na tyle, że nie będzie używać go w tej formie):

template<typename T, int... N> 
struct lookup_table_expand { 
}; 

lookup_table_expand<uint16_t, 2048> będzie pasował następujące partial specialization pierwotnego szablonu:

template<typename T, int L, int... N> 
struct lookup_table_expand<T, L, N...> : 
     lookup_table_expand<T, L - 1, look_up_table_elem<T>(L - 1), N...> { 
}; 

Ponieważ spadku szablon powyżej będą rekurencyjnie tworzony z uprawy szablon parameter list do bieżącego wzorca nie pasuje do następnego częściowego specjalizacji pierwotnego TEM Płyta:

template<typename T, int... N> 
struct lookup_table_expand<T, 1, N...> { 
    static constexpr std::array<T, sizeof...(N) + 1> values = {{ 
     look_up_table_elem<T>(0), N... 
    }}; 
}; 

Mecz z matrycą powyżej będzie się zdarzyć, gdy L staje 1 w rekursji. W tym momencie listę parametrów szablonu (N...) zawiera wyniki odwołaniu się do następującej funkcji o wartościach od 1 do 2047:

constexpr uint16_t look_up_table_elem(int i) { 
    return round(cos(static_cast<long double>(i)/2048 * 3.14159/4) * 32767); 
} 

To gdzie jedynym członkiem lookup_table_expand matrycy (values) zostanie inicjalizowane wartości listy parametrów szablonu.

Należy zauważyć, że values jest członkiem static constexpr danych, który może być inicjowany w zgłoszeniu class/struct zatem dodaje się linia nie są konieczne:

template<typename T, int... N> 
constexpr std::array<T, sizeof...(N) + 1> lookup_table_expand<T, 1, N...>::values; 

Tablica values będzie dziedziczony przez lookup_table_expand<uint16_t, 2048>, więc w koniec możesz uzyskać do niego dostęp z tej struktury.

+1

Bardzo dobre wyjaśnienie, sprawia, że ​​rzeczy stają się bardziej przejrzyste! – Nirri