array
C++11
constexpr

アグリゲートに於ける要素数不定の配列の初期化と同様にstd::arrayを定数として初期化する

目的

配列を初期化する時、扱うデータによっては要素数が頻繁に変化したり、コード表面上からは分かりにくい事がしばしばある。その様な場合は、配列の宣言の際、[]で要素数を指定せず、アグリケートの初期化リストによって要素数を決定する事ができる。例えば、以下の様なコードである。

// 要素数は5
int array[] = {
  1,2,3,4,5
};

この様な配列は、初期化によって要素数が決定する為、型に要素数を指定するstd::arrayでは対応できない。

#include <array>
// テンプレート引数に要素数5を渡さなければならない
std::array<int, 5> array = {{
  1,2,3,4,5
}};

ここでは、前述の配列と同じ様に、初期化リストの要素数と同じ要素数をもつstd::arrayを定数として作りたいとする。

方法

初期化リストをstd::initializer_listとして扱うとbegin,endによる操作や要素のコピー等によってconstexprで定数式にする事が難しい。しかし、関数テンプレートにパラメータパックによる可変個数の仮引数をとる事で、可変個数の初期値を受け取り、sizeof...演算子によって、その個数を得る事が可能である。また、関数のconstexpr指定子によって定数式としてstd::arrayを初期化する事が可能である。関数の戻り値をautoで受ける事で型の変更に対応すればよい。

具体的には以下の様なコードである。

#include <array>
#include <iostream>

template <class T, class... ARGS>
constexpr auto make_array(ARGS... args) -> std::array<T, sizeof...(ARGS)>
{
  return std::array<T, sizeof...(ARGS)>{{ args... }}; // rvalue-refとstd::forwardを使用しない事に注意
}

int main()
{
  constexpr auto a = make_array<int>(1,2,3,4,5);
  static_assert(a.size() == 5, "");
  for (auto&& it : a) { std::cout << it << std::endl; }
}

定数aは、make_arrayによって5つの要素で初期化された定数のstd::arrayである。
また、static_assertにより、その要素数が定数的に5である事を確認できる。

以上