J'aimerais avoir une structure (ou quelque chose de similaire) en C ++, qui permettra l'accès à ses membres de manière dynamique. Il devrait avoir un getter générique et des setters qui reçoivent le nom de membre en tant que chaîne et renvoient une sorte de type variant (par exemple Je pensais que cela pourrait être mis en œuvre en utilisant Que pensez-vous? Mon idée travaillerait-elle? Connaissez-vous d'autres moyens d'accomplir mon objectif? P> boost :: variante code>). P>
boost :: Fusion :: map code>, en ajoutant une chaîne représentant le nom de chaque membre et construisez une carte STL entre les fonctions Strings et Getter ou Setter. Je ne veux pas réinventer la roue, alors j'espérais quelque chose de similaire existait déjà. P>
3 Réponses :
Vous demandez Réflexion en C ++, qui, je pense, n'est pas disponible. Vous devrez vous proposer de vous-même. P>
RTTI est disponible en C ++, vous pensez à réflexion i> ... :)
Oui, la réflexion en C ++ rendrait beaucoup plus simple. Je vais me contenter d'une solution nécessitant de nouvelles lignes de code minimes pour ajouter un nouveau champ.
Fusion est une approche, mais pourquoi ne pas stocker vos "champs" dans un IE P> std :: mapp code> à clé par un
std :: string code>, où la charge utile est la Boost :: Variante Code> ...
class foo
{
public:
typedef boost::variant<int, double, float, string> f_t;
typedef boost::optional<f_t&> return_value;
typedef map<string, return_value> ref_map_t;
foo() : f1(int()), f2(double()), f3(float()), f4(string()), f5(int())
{
// save the references..
_refs["f1"] = return_value(f1);
_refs["f2"] = return_value(f2);
_refs["f3"] = return_value(f3);
_refs["f4"] = return_value(f4);
_refs["f5"] = return_value(f5);
}
int getf1() const { return boost::get<int>(f1); }
double getf2() const { return boost::get<double>(f2); }
float getf3() const { return boost::get<float>(f3); }
string const& getf4() const { return boost::get<string>(f4); }
int getf5() const { return boost::get<int>(f5); }
// and setters..
void setf1(int v) { f1 = v; }
void setf2(double v) { f2 = v; }
void setf3(float v) { f3 = v; }
void setf4(std::string const& v) { f4 = v; }
void setf5(int v) { f5 = v; }
// key based
return_value get(string const& key)
{
ref_map_t::iterator it = _refs.find(key);
if (it != _refs.end())
return it->second;
return return_value();
}
template <typename VT>
void set(string const& key, VT const& v)
{
ref_map_t::iterator it = _refs.find(key);
if (it != _refs.end())
*(it->second) = v;
}
private:
f_t f1;
f_t f2;
f_t f3;
f_t f4;
f_t f5;
ref_map_t _refs;
};
int main(void)
{
foo fancy;
fancy.setf1(1);
cout << "f1: " << fancy.getf1() << endl;
fancy.set("f1", 10);
cout << "f1: " << fancy.getf1() << endl;
return 0;
}
Cela fonctionnerait, mais je préfère avoir une vérification de type stricte et un accès d'exécution plus rapide dans les cas où je connais le nom de champ à la compilation.
D'accord, dans ce cas de magasin dans la carte, références aux champs réels (qui sont de type variante - exemple ci-dessus) ...
Le problème ici est qu'il y a 5 endroits où j'ai besoin d'ajouter un nouveau champ. Cela ressemble à beaucoup de chaudière pour ajouter ce qui est constitué uniquement d'un nom de compilation, d'une chaîne et de type. Peut-être que je pourrais modifier votre solution en ayant les champs publics (et avec leur type non variant) et en stockant sur la carte une sorte d'emballage qui s'est converti à partir d'une variante.
J'ai finalement écrit quelque chose de plus complexe: au lieu de conserver une carte avec des variantes, j'ai créé une carte qui avait des clés de chaîne et des fonctions getter et de réglage pour les valeurs. Les getters and Setters ont ensuite accédé à un boost :: Fusion :: Objet de la carte pour obtenir les valeurs réelles. Mais cette solution était plus compliquée que nécessaire ...
Qu'est-ce que j'ai fait pour cela était un boost :: Liste de types semblable à celle qui contient mes membres et une sorte de description. Je construis ensuite cette cartographie en ajoutant de mes membres à une structure de données "méta-info" par des appels de fonction "chaînées". Le tout semble très semblable à la définition d'une classe à Boost.python. Si vous utilisez réellement boost :: Inconférence, il devrait également fonctionner comme une séquence dans Boost.Fusion, vous pouvez donc itérité bien sur vos données. Peut-être que vous pouvez utiliser une carte boost.fusion plutôt pour obtenir le journal (n) les temps d'accès au temps d'exécution, mais il semble que leur taille soit limitée jusqu'à ce que des modèles variadiques soient disponibles. p>
Je pense que les deux boost boost :: Fusion :: Carte et Boost :: Inconférences ont une (1) accès à l'heure d'exécution.
Je me demande pourquoi tu veux ça? Même dans des langues qui l'appuient directement, la réflexion est un piratage utilisé pour contourner le code néfaste ou le code bon marché pour les programmeurs paresseux.
Vous vaincuez la sécurité C ++ vous donne. Qu'est-ce que sur Terre peut justifier d'échanger un tel outil simple et fort pour l'exactitude avec un hack désordonné pour obtenir une incertitude?
@wilhelmtell: J'essaie de trouver le bon équilibre. Je lis des valeurs d'une source très incertaine et ils doivent être analysés et gérés de manière générique. Seulement pour une petite partie d'entre eux, je connais (et je veux savoir) le bon type.
@Dibling: J'ai toujours pensé que les programmeurs paresseux où les meilleurs programmeurs ...
Donc, sur l'utilisation d'un conteneur standard de différents types plutôt que d'une structure?
Je veux que cela établisse une classe de base sérialisable, je peux donc simplement déclarer les noms et types de champs, et à partir de ces informations générer des fonctions Serialize et non désériorize. Pour le moment, je répète les noms de champs aux deux endroits, ce qui va être mauvais à l'avenir.