Entweder du nimmst dir dafür eine Drittbibliothek, baust dir selber eine schön verpackte Klasse, oder nutzt folgende sehr einfache Implementierung:
#include <filesystem> // path
#include <fstream> // ifstream, ofstream
#include <iostream> // cout
#include <string> // string
#include <tuple> // apply, make_tuple
template <class ... ARGS>
[[nodiscard]] inline auto load(const ::std::filesystem::path & fnam, ARGS && ... args) {
using namespace ::std;
static_assert(sizeof...(ARGS), "no args supplied");
auto result { make_tuple(args ...) };
if (ifstream ifs { fnam }; ifs.good()) {
ifs.exceptions(ifstream::failbit);
ifs.setf(ifstream::boolalpha);
apply([&ifs] (ARGS & ... refs) { (ifs >> ... >> refs); }, result);
}
return result;
}
template <class ... ARGS>
inline void store(const ::std::filesystem::path & fnam, ARGS && ... args) {
using namespace ::std;
static_assert(sizeof...(ARGS), "no args supplied");
ofstream ofs { fnam };
ofs.exceptions(ifstream::failbit | ifstream::badbit);
ofs.setf(ofstream::boolalpha);
auto printer { [&ofs] (const auto & ref) {
ofs << ref << endl;
} };
(printer(args), ...);
}
int main() {
using namespace ::std;
cout.setf(ios_base::boolalpha);
const string cfg_file { "./config.txt" };
auto [my_int, my_float, my_bool, my_char] {
load(cfg_file, 123, 456.789f, true, 'A')
};
cout << "[LOADED]" << endl;
cout << my_int << endl;
cout << my_float << endl;
cout << my_bool << endl;
cout << my_char << endl;
cout << endl;
my_int *= 2;
my_float += 123.456f;
my_bool = !my_bool;
my_char = my_char == 'A' ? 'Z' : 'A';
store(cfg_file, my_int, my_float, my_bool, my_char);
cout << "[STORED]" << endl;
cout << my_int << endl;
cout << my_float << endl;
cout << my_bool << endl;
cout << my_char << endl;
cout << endl;
}
Guck dir in der main()-Funktion an, wie es genutzt wird.
Der Typ wird automatisch von den Initialwerten genutzt, die an load() übergeben werden, sodass man ihn bei den einzelnen Variablen nicht angeben muss.
Beachte bitte, dass du einen C++17-fähigen Compiler nutzen musst, weil der obige Code exzessiv moderne Sprachfeatrues nutzt!
Alles in allem kannst du deine Werte dann beim Programmstart mit ...
auto [a, b] { load("datei.txt", 23, 42.42) };
... laden, und am Ende mit ...
store("datei.txt", a, b);
... speichern. Existiert am Anfang noch keine Datei (oder kann diese nicht geöffnet werden), werden die Variablen stillschweigend mit den angegebenen Werten initialisiert. Ansonsten wird bei Schreib- und Lesefehlern eine Ausnahme geworfen.
Das ist zwar nicht so sicher, wie eine hübsch gekapselte Klasse, weil evtl. Werte vertauscht werden könnten, aber es erfordert dafür nur ein paar Zeilen Code. :)