読者です 読者をやめる 読者になる 読者になる

とくにあぶなくないRiSKのブログ

危ないRiSKのブログだったかもしれない。本当はRiSKだけどググラビリティとか取得できるIDの都合でsscriskも使ったり。

constexpr で扱えて,実行時の効率もよいデータ構造+アルゴリズム

union 使ってキメラにすればいいと気が付いた。
コンパイル時はリストとして扱い,実行時には配列として扱います。なんとなくアルゴリズムも書けたので合わせて CEL に組み込む予定。
次の例はコンパイル時に [0, 20) の配列を作って実行時に出力。んで,コンパイル時にその配列を元に各要素を2倍した配列を作って実行時に出力してます。

#include<cstddef>
#include<array>
#include<iostream>

template<class T, std::size_t N>
struct list
{
 T value;
 list<T, N - 1> next;
};

template<class T>
struct list<T, 1>
{
 T value;
};

template<class T>
constexpr list<T, 1> iota(list<T, 1> const & , T value)
{
 return {value};
}

template<class T, std::size_t N>
constexpr list<T, N> iota(list<T, N> const & , T value)
{
 return {value, iota(list<T, N - 1>(), value + 1)};
}

template<class T, class UnaryOperation>
constexpr list<T, 1> transform(list<T, 1> const & l, UnaryOperation op)
{
 return {op(l.value)};
}

template<class T, std::size_t N, class UnaryOperation>
constexpr list<T, N> transform(list<T, N> const & l, UnaryOperation op)
{
 return {op(l.value), transform(l.next, op)};
}

template<class T, std::size_t N>
union chimera
{
 list<T, N> compile_time;
 std::array<T, N> run_time;
 static_assert(sizeof(compile_time) == sizeof(run_time), "");
};



int main()
{
 constexpr chimera<unsigned, 20> melpon{iota(list<unsigned, 20>(), 0U)};
 for(auto n: melpon.run_time)
  std::cout << n << ", ";
 std::cout << std::endl;

 struct twice{constexpr unsigned operator()(unsigned n){return n * 2;}};
 constexpr chimera<unsigned, 20> melponn{transform(melpon.compile_time, twice())};
 for(auto n: melponn.run_time)
  std::cout << n << ", ";
}

実行結果:

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38,

union 使うあたりが非常に規格的に怪しいけど,「sizeofが同じならいいよね」的な楽観視。問題があればご指摘を。
こんな感じで使えれば,sin, cos, tan の表なんかもコンパイル時に作れそうですよ!!!