いいえ
C++ には、イントロスペクションとリフレクションの機能がありません。この種の動的アクセスは、自分でコーディングする必要があります。
ハンド コーディングに代わる合理的な方法として、場合によっては、外部スキーマ ファイルを使用して C++ クラスを記述し、クラスとイントロスペクションおよびリフレクション コードを自動的に生成することができます。テンプレートを使用してこれを行うことはできません。C++ のメタプログラミング機能でさえ、この領域にはまったく存在しないからです。
一般に、直接解析.h
してコードを生成することは、C++ 構文が非常に複雑であるため、はるかに困難になる可能性があります (コンパイラ メーカーでさえ、有効な C++ コードとそうでないものについてかなりの程度に同意するのにかなりの年月がかかりました)。
テンプレートを使用して公開を簡素化できますが、手動で行うこともできます。
template<typename T, typename C>
std::map<std::string, T C::*>& attribute_map() {
static std::map<std::string, T C::*> m;
return m;
}
template<typename C>
struct Published {
template<typename T>
T& attribute(const std::string& name) {
std::map<std::string, T C::*>& m = attribute_map<T, C>();
typename std::map<std::string, T C::*>::const_iterator i=m.find(name);
if (i == m.end()) {
throw std::runtime_error("Attribute not present");
} else {
return static_cast<C *>(this)->*i->second;
}
}
};
各属性について、明示的に「公開」する必要があります
template<typename T, typename C>
void publish(const std::string& name, T C::*mp) {
attribute_map<T, C>()[name] = mp;
}
上記のボイラープレート コードを指定すると、クラスを作成し、次のように派生してそのメンバーの一部を公開できますPublished<Class>
。
struct MyClass : Published<MyClass> {
int a;
double b;
std::string c;
MyClass(int a, double b, const std::string& c)
: a(a), b(b), c(c)
{
}
};
次に、プログラムの開始時に一度だけ関数を呼び出して、publish
属性に動的にアクセスできるようにする必要があります。
int main(int argc, const char *argv[]) {
publish("a", &MyClass::a);
publish("b", &MyClass::b);
publish("c", &MyClass::c);
MyClass m1(3, 4.5, "This is a test");
MyClass m2(6, 7.8, "This is another test");
std::cout << m1.attribute<int>("a") << "\n";
std::cout << m2.attribute<std::string>("c") << "\n";
return 0;
}