[象の卵] 構造体のメンバ数の取得方法?

Cの構造体のメンバ数を取得したいという要望があるようです。Cの構造体は、あくまでもコンパイル時だけの概念であり、実行時には情報が失われてしまいます。ですので、実行時にメンバ数やメンバの型、あるいはメンバ名を取得することはできません。どうしてもやりたければ、構造体とは別に自分で情報を管理するしかありません。ここまではnoocyteさんも指摘されています。

一般的な構造体が相手だと、CであれC++であれ、ここで終わりになってしまいます。しかし、後からメンバ数などの情報を取得したい構造体については、定義方法をちょっと工夫することで何とかなるかもしれません。また、実行時に取得できなくても、マクロやテンプレートを使って取得できるのであれば、それなりに使い道があるはずです。

C++のテンプレートを使って情報を取得できればよいのであれば、tupleを使えば簡単です。

tuple<int, double, const char*> t(123, 1.23, "abc");
cout << get<0>(t) << endl;
cout << get<1>(t) << endl;
cout << get<2>(t) << endl;

ただ、tupleはC++03の標準ライブラリには含まれません。そのため、TR1を使うか、Boost C++ Librariesを使うか、C++0xを使う必要があります。どのtupleを使うかによって、名前空間もstd:tr1, boost, stdの3種類を使い分けることになります。要素数を求めるにはtuple_sizeを使いますが、(型ではなく)オブジェクトから要素数を求めるには、一度関数を介したほうが楽でしょう。

template <class T>
size_t size(const T& t)
{
  return tuple_size<T>::value;
}

本来であれば、テンプレート引数はTではなく、tupleのテンプレート引数にすべきなのですが、可変長のテンプレート引数をサポートしているかどうかで指定方法が変わってきて面倒なので、とりあえずこうしておきましょう。

もともとはCの構造体のメンバ数を取得したいという要望ですので、C++でできたとしても、それでは無意味かもしれません。Cの場合は、いずれにしても別途管理するためのオブジェクトまたはマクロを定義せざるを得ないのですが、記述の煩雑さを緩和することさえできれば、結構使えるようになる可能性があります。

普通はプリプロセッサを駆使して実現することになるのですが、どう頑張っても記述を簡便化するには限界があります。そこで、PCPの出番となります。

<?php
function struct($arg)
{
  echo "struct ${arg[0]} {\n";
  foreach ($arg as $name => $type)
  {
    echo "\t$type $name;\n";
  }
  echo "};\n";
}
 
$foo = array('foo', 'a' => 'int', 'b' => double, 'c' => 'const char*');
struct($foo);
?>

上のコードのうち、struct関数の定義は一度行うだけで構いませんし、再利用も可能です。あとは、変数$fooがあれば、メンバ数を取得することも、それぞれのメンバの型や名前を取得することも可能になります。邪道といえば邪道かもしれませんが、象の卵というキメラのような存在を作ろうというわけですから、これぐらいはやむを得ないでしょう。

この記事のトラックバックURL:

http://www.kijineko.co.jp/trackback/896
このエントリーを含むはてなブックマーク