Можно ли создать пустую структуру, а потом её заполнить внутри функции?
Нет, в языке c++ все типы данных должны быть известны компилятору при компиляции программы.
Для работы с текстовыми настройками программы есть готовые решения, например
qsettings в qt,
libconfig.
Если нужна своя реализация, можно придумать разные варианты интерфейсов для
class Config
. Если нам нужны отдельные объекты вроде
struct Date
, можем реализовать фабричный метод, который будет их создавать, как в следующем примере.
#include <iostream>
#include <string>
#include <unordered_map>
#include <fstream>
class AppConfig {
public:
static AppConfig make(const std::string& path) {
auto attributes = readAttributes(path);
if (attributes.empty()) {
// signal error - no attributes, no config
return {};
}
return parse(attributes);
}
std::string title = "";
bool fullscreen = false;
bool windowMode = false;
int width = 0;
int height = 0;
int renderApi = 0;
private:
static std::unordered_map<std::string, std::string>
readAttributes(const std::string& path) {
std::unordered_map<std::string, std::string> attributes;
std::ifstream configFile(path);
if (!configFile) {
// signal error - failed to open file
return {};
}
std::string attribute, value;
while (configFile >> attribute >> value) // attribute value
attributes[attribute] = value;
return attributes;
}
static AppConfig parse(std::unordered_map<std::string, std::string>& attributes) {
static constexpr auto trueValue = "true";
AppConfig config;
config.title = attributes["title"];
config.fullscreen = attributes["fullscreen"] == trueValue;
config.windowMode = attributes["window_mode"] == trueValue;
config.width = std::stoi(attributes["width"]);
config.height = std::stoi(attributes["height"]);
config.renderApi = std::stoi(attributes["render_API"]);
return config;
}
};
class Window {
public:
static bool create_window(...) { return true; }
};
bool initialize() {
auto config = AppConfig::make("settings.txt");
if (!Window::create_window(config.title, config.fullscreen, config.windowMode,
config.width, config.height))
return false;
//...
return true;
}
Класс Config может иметь интерфейс словаря, который можно реализовать с помощью std::any. При этом можно убрать промежуточные классы и всегда обращаться непосредственно к Config.
#include <unordered_map>
#include <string>
#include <any>
class AppConfig {
public:
explicit AppConfig(const std::string& path) { /* read values */ }
std::any operator[](const std::string& attribute) { return attributes[attribute]; }
private:
std::unordered_map<std::string, std::any> attributes;
};
class Window {
public:
static bool create_window(...) { return true; }
};
bool initialize() {
auto config = AppConfig("settings.txt");
if (!Window::create_window(
std::any_cast<std::string>(config["title"]),
std::any_cast<bool>(config["fullscreen"]),
std::any_cast<bool>(config["window_mode"])
/* ... */)) {
return false;
}
return true;
}