constexpr で扱えて,実行時の効率もよいデータ構造+アルゴリズム - 危ないRiSKのブログ
コンパイル時に配列を結合する - iorateの日記
index_tuple を使って constexpr な生配列から std::array への変換の処理をする配列を書いてみました.
int main() { // コンパイル時に変換する constexpr int ints[] = {1, 2, 3}; constexpr auto arr3 = to_array(ints); // std::array の operator[] は非 constexpr static_assert( arr3._M_instance[0]==1 && arr3._M_instance[1]==2 && arr3._M_instance[2]==3, "" ); // 実行時呼び出しもOK char chars[] = "foobar"; for(auto const& c : to_array(chars)){ std::cout << c << std::endl; } }
実装はこんな感じ.
#include <cstddef> #include <array> template< std::size_t... Indices > struct index_tuple{}; template < std::size_t Start, std::size_t Last, class Acc = index_tuple<>, bool Finish = (Start>=Last) > struct index_range{ typedef Acc type; }; template < std::size_t Start, std::size_t Last, std::size_t... Indices > struct index_range< Start, Last, index_tuple<Indices...>, false > : index_range<Start+1, Last, index_tuple<Indices..., Start>> {}; template <class T, std::size_t N, std::size_t... Indices> constexpr std::array<T, N> to_array_impl( T const(& native_array)[N], index_tuple<Indices...>) { return {{ native_array[Indices]... }}; } template <class T, std::size_t N> constexpr std::array<T, N> to_array( T const(& native_array)[N]) { return to_array_impl( native_array, typename index_range<0, N>::type() ); }
index_range でアクセスしたい添字の列 0,1, ... ,N-1 の可変長パラメータパックを作成し,index_tuple でそれを受け取ります.
これの良いところは冒頭に書いたエントリーでも述べられていますが,関数呼び出し回数が抑えられ,コンパイル時だけでなく実行時にも良いパフォーマンスで実行できるところです.constexpr の機能をうまく利用できています.