可変個の引数とnon-POD型

まず、可変個の引数を取る関数の書き方のおさらい。


#include
uint sum(uint num, ...)
{
uint retval = 0;
va_list ap;
va_start(ap, num);

for(uint i= 0; i < num; i++)
{
retval += va_arg(ap, uint);
}

va_end(ap);
return retval;
}

こんな感じで、num個のuint型を足し合わせる関数が定義できる。
しかし、va_argで読み出せる型はPOD型(PODはPlain Old Dataの略)に限られる。コンストラクタやデコンストラクタがユーザー定義だったりすると、non-POD型になってしまう(PODとnon-PODの正確な定義はよくわからん)。そういった型を引数に取りたい場合は、ポインタでデータを渡してやれば良い。

#include
cmtrx tensor_prod(uint num, ...)
{
if(!num){return cmtrx();}

va_list ap;
va_start(ap, num);

cmtrx output = va_arg(ap, const cmtrx &);

for(uint i = 1; i < num; i++)
{
output = tensor_prod(output, va_arg(ap, const cmtrx &));
}

va_end(ap);
return output;
}

これはダメだけど、

#include
cmtrx tensor_prod(uint num, ...)
{
if(!num){return cmtrx();}

va_list ap;
va_start(ap, num);

cmtrx output = *va_arg(ap, const cmtrx *);

for(uint i = 1; i < num; i++)
{
output = tensor_prod(output, *va_arg(ap, const cmtrx *));
}

va_end(ap);
return output;
}

これならOK。ちなみに上記のcmtrx型はboostの複素行列で、

#include
typedef std::complex cmplx;
typedef boost::numeric::ublas::matrix cmtrx;
こんな感じに定義したものです。