2012-06-05 11 views
13

Mein Ziel ist es, globale Konstanten in einem C++ - Spiel zu haben, an dem ich gerade arbeite (um einige Grafikinformationen und ähnliches darzustellen). Meine derzeitige Implementierung besteht darin, sie alle in eine .h zu werfen und sie überall einzubeziehen. Dies funktioniert, außer dass jedes Mal, wenn ich eine Einstellung ändere, die gesamte Codebasis neu kompiliert werden muss.Korrekte Implementierung der globalen Konfiguration

Also, meine nächste Idee war es, sie in einige Konfigurations-TXT-Datei werfen und analysieren sie, auf diese Weise wird kein Code tatsächlich geändert, wenn sich die Einstellungen ändern. Der Parser war einfach genug und ich konnte die Werte in die Konstanten schreiben, aber da der Parser ein Codeblock war, waren die Konstanten nicht länger global.

Gibt es einen guten Weg, dies zu lösen? Vielleicht eine Möglichkeit, sie global zu machen, auch wenn sie in einem Block sind oder irgendwie vermeiden, alles neu zu kompilieren, wenn man die Einstellungen ändert?

Antwort

11

Eine andere Möglichkeit wäre das Erstellen einer Singleton-Klasse.

#include <fstream> 
#include <map> 
#include <string> 

class ConfigStore 
{ 
public: 
    static ConfigStore& get() 
    { 
     static ConfigStore instance; 
     return instance; 
    } 
    void parseFile(std::ifstream& inStream); 
    template<typename _T> 
    _T getValue(std::string key); 
private: 
    ConfigStore(){}; 
    ConfigStore(const ConfigStore&); 
    ConfigStore& operator=(const ConfigStore&); 
    std::map<std::string,std::string> storedConfig; 
}; 

Hier ist die Konfiguration in einer Karte gespeichert wird, was bedeutet, solange parseFile die Datei lesen und getValue den Typ gibt es keine Notwendigkeit, die Config-Klasse analysieren kann neu kompiliert werden, wenn Sie neue Schlüssel hinzuzufügen.

Verbrauch:

std::ifstream input("somefile.txt"); 
ConfigStore::get().parseFile(input); 
std::cout<<ConfigStore::get().getValue<std::string>(std::string("thing"))<<std::endl; 
+0

Zugegebenermaßen wollte ich das ursprünglich ohne zusätzliche Konstrukte tun, aber dies folgt mehr OO-Konventionen und funktioniert im Allgemeinen besser! Ich mochte Joachims Vorschläge auch, aber diese hat es für mich gelöst, danke! – akroy

+1

@akroy Ich stimme nicht zu. Welche Art von OO-Konventionen meinst du hier überhaupt? Wir haben ein Singleton. Die Lösung eines Programmierers scheint dem Einführen eines Singletons, das im Grunde um eine 'std :: map' herum aufgebaut ist, mit langsamer Suche und ohne Typsicherheit ohne wirklichen Nutzen gegenüber blanken Variablen klar überlegen zu sein. – IceFire

+0

Hey IceFire! Für den Kontext ist diese Frage vor 5 Jahren, als ich zum ersten Mal lernte zu programmieren. Wenn ich mir den Kommentarthread ansehe, sieht es so aus, als ob ich Theoretiker-Lösung eines Programmierers auch in der Theorie vorziehen würde, aber ich konnte es nicht über den Compiler hinausbekommen. Also, wenn es für dich kompiliert, mehr Macht für dich. :) – akroy

1

Legen Sie nur die Deklarationen in Kopfdatei und setzen Sie die Definitionen in eine cpp-Datei. dann ändern Sie die Definitionen in CPP-Datei wird nicht dazu führen, dass alle Code neu kompiliert

2

Was ist mit dem Erstellen von Funktionen, die Ihre Konstanten zurückgeben, die Sie in einer .cxx-Datei angeben können? Zum Beispiel:

// foo.h 
const int BAR(); 

// foo.cxx 
const int BAR() { 
    return 10; 
}; 
17

Die Art und Weise habe ich lösen diese die Variablen in einem separaten globalen Namensraum zu setzen ist, die in einer Header-Datei so etwas wie config.h benannt ist, dann sind die überall Datei.

// In config.h 

#ifndef CONFIG_H 
#define CONFIG_H 

namespace config 
{ 
    extern int some_config_int; 
    extern std::string some_config_string; 

    bool load_config_file(); 
} 

#endif 

Die in einer Quelldatei, Sie die Variable definieren und diese auch auf einen Standardwert gesetzt. Diese Quelldatei enthält auch den Code zum Laden der Variablen aus Ihrer Konfigurationsdatei.

// In config.cpp 

namespace config 
{ 
    int some_config_int = 123; 
    std::string some_config_string = "foo"; 
} 

bool config::load_config_file() 
{ 
    // Code to load and set the configuration variables 
} 

nun in jeder Quelldatei müssen Sie die Konfigurationsvariablen umfassen config.h und greifen Sie wie config::some_config_int.

Allerdings gibt es keine "richtige" Art und Weise, dies zu lösen, alle Möglichkeiten, die Arbeit in meinen Augen richtig sind.

+0

Diese Lösung klingt wirklich ideal, weil es mich in einer Konfigurationsdatei geladen werden kann, so könnte ein Benutzereinstellung ändern, ohne Compilierung. Aber ich habe versucht, die Code-Logik, die Sie verwendet haben, zu imitieren, und ich bekomme "undefinierten Verweis auf" config :: VARIABLE_NAME "" "jedes Mal, wenn eine Variable verwendet wird. Auch wenn ich keine load-Funktion verwendet und rein definiert die Variablen in der .cpp, ich habe den gleichen Fehler. (Ich habe die exakt gleiche Syntax wie Sie mit extern in .h und vollständige Deklaration und Definition in .cpp) – akroy

+0

@Akroy Sie erstellen/verknüpfen mit der neuen Quelldatei? –

+0

Ich tat das. Also, wenn config.h namespace config {extern int x;} hat, config.cpp hat namespace config {int x = 5;}, dann in einer anderen Datei, die #include "config.h" hat, sollte ich in der Lage zu config :: x zugreifen? Gibt es etwas, das ich vermisse? – akroy

Verwandte Themen