2010-04-16 8 views
0

J'écris du code qui pourrait vraiment faire avec une simple métaprogrammation de temps de compilation. Il est courant d'utiliser des balises struct-empty comme symboles de compilation. J'ai besoin de décorer les balises avec des éléments de configuration d'exécution. les variables statiques semblent être la seule solution (pour activer la méta-programmation), mais les variables statiques nécessitent des déclarations globales. à côté de cette suggestion de Scott Myers (à partir de la troisième édition d'Effective C++), sur le séquençage de l'initialisation de variables statiques en les déclarant à l'intérieur d'une fonction au lieu de variables de classe, est venu à l'esprit.Méta-programmation de temps de compilation, avec littéraux de chaîne

Donc, je suis venu avec le code suivant, mon hypothèse est qu'il me laissera avoir un symbole de compilation avec des littéraux de chaîne utilisable à l'exécution. Je ne manque rien de ce que j'espère, et cela fonctionnera correctement, tant que je remplis les champs d'exécution avant d'initialiser les classes de modèles dépendantes. .

#include <string> 

template<class Instance> 

class TheBestThing { 
public: 
    static void set_name(const char * name_in) { 
     get_name() = std::string(name_in); 
    } 
    static void set_fs_location(const char * fs_location_in) { 
     get_fs_location() = std::string(fs_location_in); 
    } 
    static std::string & get_fs_location() { 
     static std::string fs_location; 
     return fs_location; 
    } 
    static std::string & get_name() { 
     static std::string name; 
     return name; 
    } 
}; 
struct tag {}; 
typedef TheBestThing<tag> tbt; 

int main() 
{ 
    tbt::set_name("xyz"); 
    tbt::set_fs_location("/etc/lala"); 

    ImportantObject<tbt> SinceSlicedBread; 
} 

modifier: Fait communauté wiki.

+1

@Hassan: J'ai remarqué cela tout à l'heure. Mais encore, vous pouvez utiliser de meilleurs tags :) -1 repris cependant. –

+0

les étiquettes sont entièrement appropriées pour n'importe qui recherchant une question ceci spécifique. –

+1

Mais quelle est la question? –

Répondre

1

J'ai enfin compris quel était le problème ... et votre solution ne résout pas grand-chose, le cas échéant. L'objectif de l'utilisation d'une variable statique locale est de fournir une initialisation lors de la première utilisation, étant ainsi à l'abri du "Fiasco d'ordre d'initialisation" (en passant, il ne résout pas le "Destruction Order Fiasco").

Mais avec votre conception, si vous empêchez effectivement le crash vous n'empêchez toutefois pas l'utilisation d'une variable avant que sa valeur ne soit utilisée.

ImportantObject<tbt> SinceSliceBread; // using an empty string 

tbt::set_name("xyz"); 

Comparer avec l'utilisation suivante:

std::string& tbt::get_name() { static std::string MName = "xyz"; return MName; } 

Ici, le name est non seulement créé mais aussi initialisés la première utilisation. Quel est le point d'utiliser un nom non initialisé?

Eh bien, maintenant que nous savons que votre solution ne fonctionne pas, réfléchissons un peu. En fait, nous aimerions automatiser:

struct tag 
{ 
    static const std::string& get_name(); 
    static const std::string& get_fs_location(); 
}; 

(avec peut-être des accesseurs pour les modifier) ​​

Ma première (et facile) solution serait d'utiliser une macro (bouh pas Typesafe):

#define DEFINE_NEW_TAG(Tag_, Name_, FsLocation_)    \ 
    struct Tag_             \ 
    {               \ 
    static const std::string& get_name() {     \ 
     static const std::string name = #Name_;     \ 
     return name;           \ 
    }               \ 
    static const std::string& get_fs_location() {    \ 
     static const std::string fs_location = #FsLocation_; \ 
     return fs_location;          \ 
    }               \ 
    }; 

L'autre solution, dans votre cas, pourrait être d'utiliser boost::optional pour détecter que la valeur n'a pas encore été initialisée, et remettre à plus tard l'initialisation des valeurs qui en dépendent.

+0

Oui, je n'ai pas abordé le problème du séquençage d'initialisation, Ma principale préoccupation était d'avoir un moyen facile d'utiliser les chaînes qui sont disponibles au moment de la compilation et de les associer à une étiquette de temps de compilation. Boost :: Les chaînes littérales MPI sont un peu un hack et C++ 0x résout le problème. J'ai donc choisi la technique static-string-declar-in-function du livre de Myers. Merci pour l'analyse, et votre Macro peut certainement faire lire le code plus comme une histoire. –

+0

Accepté comme réponse, car il ajoute de la valeur à la question. Cependant, beaucoup de gens ont discuté de cette question et j'ai apporté des modifications successives au code dans la question. Boost optionnel est un très bon moyen de se prémunir contre les problèmes d'initialisation. Peut-être que je vais l'ajouter, mais comme le code est destiné à un usage interne dans mon projet, je ne le ferai peut-être pas immédiatement. –

Questions connexes