次のページを見てみてください。
このページで紹介されている make_array 関数と auto による型推論を用いれば、要素数を指定せずに std::array を生成することができます。
| const auto values = make_array<int>(1, 2, 3, 4, 5);
|
なお、元記事の make_array はインライン関数ですが、次のようにすることで constexpr 関数にもできます。*1
| #include <array>
template<typename T, typename ...Args>
constexpr std::array<T, sizeof...(Args)> make_array(Args&&... args)
{
return std::array<T, sizeof...(Args)>{ static_cast<Args&&>(args)... };
}
|
これにより、型 T がリテラル型で、かつすべての引数が定数値の場合に限り、 constexpr な std::array インスタンスを要素数指定無しで作成可能になります。
| constexpr auto values = make_array<int>(1, 2, 3, 4, 5);
|
そして、 std::array の要素数を得るメンバ関数 size は constexpr 関数です。
つまり、前回の記事に書いた、「std::array を使いつつ、組み込み配列のように要素数の変更をコンパイル時検出する」ことが次の記述で可能になります。
|
constexpr auto values = make_array<int>(1, 2, 3, 4, 5);
static_assert(values.size() == ReqCount, "values size error!");
|
ただし、この方法は型 T がリテラル型の場合に限ります。
なぜなら、そうでなければ std::array<T, N> もリテラル型にならず、メンバ関数 size が constexpr 関数にならないためです。
型 T がリテラル型以外の、例えば std::string 型の場合、別の記述方法をとる必要があります。
それは次のようなコードになります。
| #include <array>
#include <type_traits>
#include <string>
const auto values = make_array<std::string>("a", "b", "c", "d", "e");
static_assert(
std::tuple_size<typename std::remove_cv<decltype(values)>::type>::value == ReqCount,
"values size error!");
|
何やら長ったらしいですが、やっていることは std::tuple_size<std::array<T, N>>::value によって要素数をコンパイル時定数として取得しているだけです。
この方法は constexpr な std::array であっても使えるので、こちらの方が汎用性の高いチェック方法であるといえます。
…とはいえ、「長ったらしくて書いてられん!」と思うことでしょう。
そこで、前回の記事で紹介した array_size 関数を std::array 用にオーバロードしてみます。*2
| #include <array>
namespace util
{
template<typename T, std::size_t N>
constexpr std::size_t array_size(const std::array<T, N>&) { return N; }
template<typename T, std::size_t N>
constexpr std::size_t array_size(T (&)[N]) { return N; }
}
|
この関数を使えば、 constexpr の有無や、型 T がリテラル型であるか否かに関わらず、次のように書くことができます。
| #include <string>
constexpr auto values = make_array<int>(1, 2, 3, 4, 5);
static_assert(util::array_size(values) == ReqCount, "values size error!");
const auto texts = make_array<std::string>("a", "b", "c", "d", "e");
static_assert(util::array_size(texts) == ReqCount, "texts size error!");
auto texts2 = make_array<std::string>("a", "b", "c", "d", "e");
static_assert(util::array_size(texts2) == ReqCount, "texts2 size error!");
|
ここまでできれば、もう std::array を使わない理由は無いですね。
なお、VC++2013でも、 make_array を constexpr 関数にせず、受け取る変数を constexpr にせず、 std::tuple_size を使って要素数をチェックする方法であればコンパイルすることができます。