@Acaunt

Можно ли создать пустую структуру, а потом её заполнить внутри функции?

В моей программе я создал структуру с параметрами а позже её заполнил:
struct Date {
    int a;
    //Множество других параметров
};
Date date;
void get_parametrs(){
    date.a = 5;
    //Присвоение значений множество других параметров
}

Я хочу узнать можно ли только 1 раз написать все параметры и присвоить им значения внутри функции, что нибудь вроде этого например:
struct Date {};
void get_parametrs(){
    Date {
    int a = 5;
    //Присвоение значений множество других параметров
    };
}
  • Вопрос задан
  • 401 просмотр
Решения вопроса 1
@code_panik
Можно ли создать пустую структуру, а потом её заполнить внутри функции?

Нет, в языке 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;
}
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@res2001
Developer, ex-admin
В плюсах структуры это те же классы, но у них по умолчанию используется модификатор доступа public, а в классах private - это вся разница между ними.
Напишите для структуры конструктор по умолчанию, в котором будете присваивать нужные значения членам структуры. После этого при объявлении любого экземпляра структуры:
Date date;
члены структуры будут принимать значения, заданные в конструкторе по умолчанию.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы