C言語の構造体のメンバ数を取得したいという要望があるようです。C言語の構造体は、あくまでもコンパイル時だけの概念であり、実行時には情報が失われてしまいます。ですので、実行時にメンバ数やメンバの型、あるいはメンバ名を取得することはできません。どうしてもやりたければ、構造体とは別に自分で情報を管理するしかありません。
一般的な構造体が相手だと、CであれC++であれ、ここで終わりになってしまいます。しかし、後からメンバ数などの情報を取得したい構造体については、定義方法をちょっと工夫することで何とかなるかもしれません。また、実行時に取得できなくても、マクロやテンプレートを使って取得できるのであれば、それなりに使い道があるはずです。
C++のテンプレートを使って情報を取得できればよいのであれば、tupleを使えば簡単です。
0 1 2 3 4 5 |
std::tuple<int, double, char const*> t(123, 1.23, "abc"); std::cout << std::get<0>(t) << std::endl; std::cout << std::get<1>(t) << std::endl; std::cout << std::get<2>(t) << std::endl; |
std::tupleはC++11からサポートされるようになりました。古い処理系を使っている場合は、TR1が使えるならstd::tr1::tupleを使えるでしょうし、それが無理ならBoost C++ Librariesを使えばboost::tupleを使うことができます。この記事ではC++11以降のstd::tupleを使うことを前提とします。
要素数を求めるにはstd::tuple_sizeを使います。C++17以降であればstd::tuple_size_vを使うこともできます。
0 1 2 3 4 5 6 7 8 |
auto size = std::tuple_size<std::tuple<int, double, char const*>>::value; // C++17以降 size = std::tuple_size_v<std::tuple<int, double, char const*>>; // std::tupleのオブジェクトから要素数を求めるにはdecltypeを使う。 size = std::tuple_size<decltype(t)>::value; size = std::tuple_size_v<decltype(t)>; |
もともとはC言語の構造体のメンバ数を取得したいという要望ですので、C++でできたとしても、それでは無意味かもしれません。C言語の場合は、いずれにしても別途管理するためのオブジェクトまたはマクロを定義せざるを得ないのですが、記述の煩雑さを緩和することさえできれば、結構使えるようになる可能性があります。
普通はプリプロセッサを駆使して実現することになります。ただ、どう頑張っても記述を簡便化するには限界があります。私はこういうときにはPHPで前処理しています。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?php function struct($arg) { echo "struct ${arg[0]} {\n"; foreach ($arg as $key => $type) { if ($key == 0) continue; echo "\t$type $key;\n"; } echo "};\n"; } $foo = [ 'foo', 'a' => 'int', 'b' => 'double', 'c' => 'const char*' ]; struct($foo); |
上のコードのうち、struct関数の定義は一度行うだけで構いませんし、再利用も可能です。あとは、変数$fooがあれば、メンバ数を取得することも、それぞれのメンバの型や名前を取得することも可能になります。邪道といえば邪道かもしれませんが、象の卵というキメラのような存在を作ろうというわけですから、これぐらいはやむを得ないでしょう。