組み込み配列の、初期化子リストによる初期化は便利ですが、要素数より少ない数だけ初期化することが許可されているため、どこまで初期化されたかがわからないところが不便です。
#include <iostream> #include <iterator> int main() { constexpr std::size_t size = 4; int data[size] = {1, 2, 3}; // 配列の要素数は4だが、初期値が入力されたのは3個 for (std::size_t i = 0; i < size; ++i) { std::cout << data[i] << std::endl; } }
1 2 3 0
その型の初期値が「使用しない値」や「無効値」として使用できるかはわからないので、こういった状況では、おとなしく可変長配列を使用するか、boost::optionalの配列にするのがいいでしょう。
しかし、それらの選択肢をとれない状況というのがあった場合のために、初期値が入力された数を取得する方法を紹介します。
#include <iostream> #define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int)) #define ARRAY(...) NUMARGS(__VA_ARGS__), {__VA_ARGS__} struct X { int size; int data[4]; }; int main() { X x = { ARRAY(1, 2, 3) }; for (int i = 0; i < x.size; ++i) { std::cout << x.data[i] << std::endl; } }
1 2 3
Xクラスのdataメンバ変数には、最大で4要素の値が入ります。sizeメンバ変数には、実際に初期値が入力された値が入ります。
xの初期化は、ARRAYマクロによって以下のように展開されます:
X x = { 3, {1, 2, 3} };
まず、配列の方は、単に可変引数マクロのパラメータを置いてるだけです。
要素数の方は、可変引数マクロのパラメータを、古典的なsizeofによる配列の要素数計算の方法によって計算しています。