# 2020q3 Homework5 (render) contributed by < `Rsysz` > ###### tags: `sysprog` {%hackmd theme-dark %} ## 編譯時期生成 lookup table 首先因為對 `C++` 一竅不通,花了不少時間在研讀各種命名與定義,考慮到對 `C++` 程式碼的理解,就先行撰寫 [編譯時期生成 lookup table](https://hackmd.io/@Rsysz/render#%E7%B7%A8%E8%AD%AF%E6%99%82%E6%9C%9F%E7%94%9F%E6%88%90-lookup-table) 的部分。 再來根據我查到的資料,撰寫 `compile time table` 通常會使用 `constexpr` ,而它是對於我們常見的 `const` 修飾子的加強,`const` 代表英文中 `constant` 常數的意思,代表被修飾的變數數值在編譯期(compile-time)已定,也無法再**通過語法**修改,任何對於標示為常數的變數的嘗試修改都會造成編譯器報錯。詳情請看 `Reference` 那我這邊也不多廢話,`constexpr` 的標準隨著 C++11, 14, 17 發展逐漸放寬,只要 `constexpr` 標記的函數內所有變數都能在**編譯時期**確認,那就能使用,因此可以透過對不同 `table` 撰寫不同的 `Generator` 大幅減少程式碼,同時保證程式的靈活度 ```cpp template <typename T, std::size_t N, typename Generator> constexpr std::array<T, N> make_array(Generator f) { std::array<T, N> table = {}; for (std::size_t i = 0; i != N; ++i) { table[i] = f(i); } return table; } ``` 使用 `array` 建構物件暫存 `for` 迴圈內運行時呼叫 `f` 輸出的數值 ```cpp constexpr auto f_tan(std::size_t i) { return static_cast<uint16_t>((256.0f * tan(i * M_PI_2 / 256.0f))); } ... constexpr static auto LOOKUP_TBL g_tan = make_array<uint16_t, TBL_LEN>(f_tan); ``` 運用上方的 `make_array` 呼叫對應的 `f_tan`,將生成的 `Table` 賦予 `const static g_tan` 另外我還有一個疑問,如果在不同檔案引入這份 header 且移除 static 宣告,是否會發生問題呢? :::warning 當然,為了使用這便利的功能是有代價地,必須使用 `c++17` 的標準來編譯才給過 ```diff -CXXFLAGS = -std=c++11 -O2 -Wall -g +CXXFLAGS = -std=c++17 -O2 -Wall -g ``` 還有因為 `raycaster_fixed` 內 `MulTan` 與 `AbsTan` 使用了 `const uint16_t *lookupTable` 的指標來傳遞陣列,但我使用了 `std::array` 來保存 `table`,因此會有轉型的問題,為此我只好 ```diff - const uint16_t *lookupTable) + auto &lookupTable) // same as const std::array<uint16_t, TBL_LEN> ``` 動了點手腳 (不知道是否允許這種改動? ::: ## Frame rate ## Reference [constexpr](https://medium.com/@tjsw/%E6%BD%AE-c-constexpr-ac1bb2bdc5e2) [Frame rate](https://thenumbat.github.io/cpp-course/sdl2/08/08.html)