正确实现全局配置

Proper implementation of global configuration

本文关键字:配置 全局 实现      更新时间:2023-10-16

我的目标是在我正在开发的C++游戏中使用全局常量(表示一些图形信息等)。我目前的实现是将它们全部扔在 .h 中并将它们包含在任何地方。这有效,除了每次更改设置时,都必须重新编译整个代码库。

因此,我的下一个想法是将它们扔到某个配置 txt 文件中并解析它们,这样当设置更改时实际上不会更改任何代码。解析器非常简单,我可以将值放入常量中,但由于解析器是代码块,因此常量不再是全局的。

有没有解决这个问题的好方法?也许某种方法使它们全局化,尽管它们处于一个块中,或者以某种方式避免在更改设置时重新编译所有内容?

我使用的解决方法是将变量放在一个单独的全局命名空间中,该命名空间位于名为 config.h 的头文件中,然后将该文件包含在任何地方。

// 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

然后在源文件中,定义变量并将其设置为默认值。此源文件还包含从配置文件加载变量的代码。

// 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
}

现在,在每个源文件中,您都需要配置变量,包括config.h并像config::some_config_int一样访问它们。

但是,没有"适当"的方法可以解决这个问题,在我看来,所有工作方式都是正确的。

执行此操作的另一种方法是创建一个单例类。

#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;
};

这里的配置保存在映射中,这意味着只要parseFile可以读取文件并且getValue可以解析类型,如果添加新键,就不需要重新编译配置类。

用法:

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

创建返回可在 .cxx 文件中指定的常量的函数怎么样? 例如:

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

只把声明放在头文件中,把定义放在 cpp 文件中。 然后你更改 cpp 文件中的定义不会导致所有代码重新编译