我正在尝试创建一个模板类,它将从给定类型的文件中读取数据到
std::variant<all possible data types (some built-in + additional specified in template)>
向量中。
A 有一个如下所示的文件:
[type] [data]
boolean true
integer 1569
string something
[...]
我想将其加载到
std::vector<std::variant<built_in_types + custom_types>
。
这是我想要做的 C++ 伪代码:
template<typename/class(?) types>
myclass {
myclass(string filename) {
ifstream file(filename);
string line_before_tab, line_after_tab;
while(getline(line_before_tab, file, '\t') && getline(line_after_tab, file, '\n')) {
for(type : built_in_types + types) {
if(type.getname() == line_before_tab) {
data.push_back(type(line_after_tab));
break;
}
}
}
file.close();
}
vector<variant<built_in_types + types>>> data;
};
如果只有内置类型,我可以为每个类型创建 if,但是对于自定义类型我该如何做呢?我对模板元编程知之甚少(我需要这个吗?)并且不知道在这种情况下该怎么做。根据需要最新的 C++。
你能帮忙吗?谢谢!
这是一个示例,使用转换函数映射和您想要使用的变体。因此,不需要您自己的模板类或元模板编程(您可以使用标准库和 C++ 功能完成几乎所有操作)。除了输出中的重载访问模式(cppreference 上有一个很好的示例)
#include <functional>
#include <iostream>
#include <iomanip>
#include <variant>
#include <string>
#include <unordered_map>
#include <sstream>
#include <vector>
struct my_struct
{
std::string value;
};
using variant_t = std::variant<bool, int, std::string, my_struct>;
using conversion_function_t = std::function<variant_t(const std::string& data)>;
using namespace std::string_literals;
variant_t convert(const std::string& type, const std::string& data)
{
static std::unordered_map<std::string, conversion_function_t> conversions
{
{"boolean",[](const std::string& data) { return variant_t{ data == "true"s }; } },
{"integer",[](const std::string& data) { return variant_t{ std::stoi(data) }; } },
{"string",[](const std::string& data) { return variant_t{data}; }},
{"struct",[](const std::string& data) { return variant_t{my_struct{data}}; }}
};
return conversions.at(type)(data);
}
auto load(std::istream& is)
{
std::vector<variant_t> items;
std::string type;
std::string data;
while (is >> type >> data)
{
items.emplace_back(convert(type, data));
}
return items;
}
// from cppreference variant doc
// helper type for the visitor #4
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
// explicit deduction guide (not needed as of C++20)
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
int main()
{
std::istringstream file{
"boolean true\n"
"integer 1569\n"
"string something\n"
"struct test\n"
};
auto items = load(file);
for (const auto& item : items)
{
std::visit(overloaded{
[](bool arg) { std::cout << "bool : " << arg << "\n"; },
[](int arg) { std::cout << "int : " << arg << "\n"; },
[](const std::string& arg) { std::cout << "string : " << std::quoted(arg) << "\n"; },
[](const my_struct& arg) { std::cout << "struct : " << std::quoted(arg.value) << "\n"; }
}, item);
}
return 0;
}