1. anqooqie

    Posted

    anqooqie
Changes in title
+[C++11] コンパイル時に概ね1000要素以上の配列を初期化する
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,64 @@
+C++11という**古代言語**では配列をコンパイル時に初期化することにも大変な苦痛が伴った。
+以下は0〜9999の数値を入力として受け取り、その2乗の値をコンパイル時に構築したルックアップテーブルから引いてきて出力するサンプルである。
+
+# サンプルコード
+
+```cpp
+#include <iostream>
+#include <array>
+
+template <int... V> struct sequence {
+ template <typename T> using join = typename T::template prepend<V...>;
+ template <int... U> using prepend = sequence<U..., V...>;
+ static constexpr std::array<int, sizeof...(V)> value = {V...};
+};
+template <int... V> constexpr std::array<int, sizeof...(V)> sequence<V...>::value;
+
+template <int I, int N> struct pow_range {
+ using to_sequence = typename pow_range<I, N / 2>::to_sequence::template join<typename pow_range<I + N / 2, N - N / 2>::to_sequence>;
+};
+template <int I> struct pow_range<I, 1> {
+ using to_sequence = sequence<I * I>;
+};
+
+int main() {
+ int x;
+ std::cin >> x;
+ std::cout << pow_range<0, 10000>::to_sequence::value[x] << std::endl;
+ return 0;
+}
+```
+
+# ポイント
+
+* テンプレートには再帰限界(C++11では推奨値1024)がある。概ね1000要素以上の大きな配列をコンパイル時に構築する場合は、再帰回数がlogNのオーダーになるよう、二分探索的にテンプレートを展開していく必要がある。
+* 外出しで`sequence<V...>::value`の行が再度無意味に書かれているように見えるが、これが無いとリンカでエラーになってしまう。以下は私の理解。
+ * `value[(実行時に決まる値)]`をするためには`value`が定義されている必要がある。
+ * 最初の`value`はただの宣言。
+ * 次の外出しの`value`が定義になっている。
+
+# C++14以降では
+
+C++14以降ではconstexprコンストラクタの中でforループを回せるので、より柔軟で簡潔なコードを書ける。
+
+```cpp
+#include <iostream>
+#include <array>
+
+template <int N> struct pow {
+ std::array<int, N> value;
+ constexpr pow() : value() {
+ for (int i = 0; i < N; ++i) {
+ value[i] = i * i;
+ }
+ }
+};
+
+int main() {
+ int x;
+ std::cin >> x;
+ std::cout << pow<10000>().value[x] << std::endl;
+ return 0;
+}
+```
+