次のページを見てみてください。
このページで紹介されている 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
を使って要素数をチェックする方法であればコンパイルすることができます。