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

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

constexpr で扱えて,実行時の効率もよいデータ構造+アルゴリズム[仕切りなおし]

昨日紹介した id:iorate さんの index_tuple を使って書き直してみました。

#include<cstddef>

template<std::size_t...>
struct index_tuple
{};

template<std::size_t Start, std::size_t Finish, class Acc = index_tuple<>, bool Break = Start >= Finish>
struct index_range
{
 typedef Acc type;
};

template<std::size_t Start, std::size_t Finish, std::size_t... Indexes>
struct index_range<Start, Finish, index_tuple<Indexes...>, false>
 : index_range<Start + 1, Finish, index_tuple<Indexes..., Start> >
{};

template<class T, std::size_t N>
struct array
{
 T elems[N ? N : 1];
 constexpr std::size_t operator[](std::size_t n)const{ return elems[n]; }
 constexpr T const * begin()const{ return elems; }
 constexpr T const * end()const{ return elems + N; }
};

template<class T, std::size_t N, std::size_t... Indexes>
constexpr array<T, N> iota_impl(array<T, N> const & , T value, index_tuple<Indexes...>)
{
 return {{(value + Indexes)...}};
}

template<class T, std::size_t N>
constexpr array<T, N> iota(array<T, N> const & a, T value)
{
 return iota_impl(a, value, typename index_range<0, N>::type());
}

template<class T, std::size_t N, std::size_t... Indexes, class UnaryOperation>
constexpr array<T, N> transform_impl(array<T, N> const & a, UnaryOperation op, index_tuple<Indexes...>)
{
 return {{op(a[Indexes])...}};
}

template<class T, std::size_t N, class UnaryOperation>
constexpr array<T, N> transform(array<T, N> const & a, UnaryOperation op)
{
 return transform_impl(a, op, typename index_range<0, N>::type());
}

#include<iostream>

constexpr int twice(int n){ return n * 2; }

int main()
{
 constexpr array<unsigned, 20> a = iota(array<unsigned, 20>(), 0U);
 for(int n: a)
  std::cout << n << ", ";
 std::cout << std::endl;

 constexpr array<unsigned, 20> b = transform(a, twice);
 for(int n: b)
  std::cout << n << ", ";
 std::cout << std::endl;
}

実行結果:

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,

すばらしいですね。前回の list や chimera は不要そうです。
constexpr に対応した array は前から必要だと思っていて,すでに書いてあります。これから CEL にも add しようかな。(最近は「しようかな」ばかりで,実際してないんだよねw)