gpt4 book ai didi

c++ - 可能从单个方法返回不同类型的对象

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:09:09 25 4
gpt4 key购买 nike

我负责重构一些解析相似(但不同的文件)的代码。它们的不同之处在于它们具有不同数量的列。假设文件类型称为 MODEL_FILECOMPANY_FILE . MODEL_FILE具有以下格式:

CAR_MODEL    CAR_COMPANY    MILEAGE

COMPANY_FILE具有以下格式:

CAR_COMPANY    MILEAGE

解析 MODEL_FILE 的结果将是 std::map<Car_Model, std::map<Car_Company, double> > ;解析 COMPANY_FILE 的结果将是 std::map<Car_Company, double> .

头文件是这样的:

typedef std::map<Car_Model, std::map<Car_Company, double> > Model_Data;
typedef std::map<Car_Company, double> Company_Data;

struct Data
{
Model_Data data_model;
Company_Data data_company;
};

bool parse_company_file(const std::string& path, Company_Data& data); // 1
bool parse_model_file(const std::string& path, Model_Data& data); // 2
bool parse_generic_file(bool is_company_file, const std::string& path, Data& data); // 3

解析代码确实在3中.两者 12内部调用 3 ,它知道(通过 bool 参数)它要解析的文件是否有 2 列或 3 列。 Data中只有一个字段将被填充(哪个取决于 bool 参数)。然后,函数调用 3将从填充的 Data 中检索结构的适当字段结构并用于填充它已传递的 map 。

这样,解析文件的代码就只在一处(3)。从外面看,代码很好(两个不同的入口点返回适当的数据),但内部实现在我看来并不正确(使用结构作为一种方法的技巧,可以使用单一方法来潜在地填充两种不同且独立的对象类型)。

我想过使用继承,这样泛型方法接收一个指向公共(public)基类的指针,该基类有两个方法(add_model_data()add_company_data())。它会根据 bool 调用一个或另一个参数。然而,这更加复杂和困惑,并且意味着通过让基类知道低类的方法来打破抽象,它容易出错等。

问题是,是否有可能以某种方式将解析逻辑保留在一个地方,但使用与 struct 不同(并且可以说更好)的方法?为了处理不同的文件?

最佳答案

std::variantboost::variant专为“或”类型而设计——A 或 B 类型。所以这是一种方法。

另一种更奇特的方法是记住有 3 个数字——0、1 和无穷大。

这种方法更难,但可以将您的解析代码重构为非常通用的代码。我不会为这个解决方案费心,所以我只是在下面画出它的草图,但它可以让您在编写后以最少的工作添加这种格式的 4 或 20 列版本。

列解析器接受一个字符串并返回一个 T 类型的值:

std::string -> T

template<class T>
using column_parser = std::function<T(std::string)>;

(我们以后可以让它更有效率)。

给定 N 列解析器,我们可以构建一个 map<T0, map<T1, map<T2, map<..., map<TN-2, TN-1>...>>>> .

template<class T0, class...Ts>
struct nested_map {
using type=T0;
};
template<class T0, class...Ts>
using nested_map_t = typename nested_map<T0, Ts...>::type;

template<class T0, class T1, class...Ts>
struct nested_map<T0, T1, Ts...> {
using type=std::map<T0, nested_map_t<T1, Ts...>>;
};

这让我们可以获取一组类型并生成一个映射。

template<class...Ts>
nested_map_t<Ts...> parse_file(std::string path, column_parser<Ts...> columns);

这会将任意数量的列解析为嵌套映射。

你公开:

bool parse_company_file(const std::string& path, Company_Data& data) {
column_parser<Car_Company> company = // TODO
column_parser<double> milage = // TODO
try {
data = parse_file( path, company, milage );
} except (some_error) {
return false;
}
return true;
}
bool parse_model_file(const std::string& path, Model_Data& data) {
column_parser<Car_Model> model = // TODO
column_parser<Car_Company> company = // TODO
column_parser<double> milage = // TODO
try {
data = parse_file( path, model, company, milage );
} except (some_error) {
return false;
}
return true;
}

现在,写parse_file ,我们做类似(伪代码)

template<class...Ts>
nested_map_t<Ts...> parse_file(std::string path, column_parser<Ts...> columns) {
nested_map_t<Ts...> retval;

auto f = open_file(path);

for( std::string line: get_lines(f)) {
std::vector<std::string> column_data = split_into_columns(line);
if (sizeof...(Ts) != column_data.size()) throw some_error;
index_upto<sizeof...(Ts)>()([&](auto...Is){
recursive_insert(retval, columns(column_data[Is])...);
});
}
return retval;
}

哪里index_uptothis in C++14或替换为手动包扩展和辅助函数,以及 recursive_insert(m, t0, ts...)采用“嵌套 map ”M& m和一堆元素 T const&并递归执行 recursive_insert(m[t0], ts...)直到有 1 个元素并且它执行 m = t0 .

关于c++ - 可能从单个方法返回不同类型的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44587544/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com