- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我负责重构一些解析相似(但不同的文件)的代码。它们的不同之处在于它们具有不同数量的列。假设文件类型称为 MODEL_FILE
和 COMPANY_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
中.两者 1
和 2
内部调用 3
,它知道(通过 bool 参数)它要解析的文件是否有 2 列或 3 列。 Data
中只有一个字段将被填充(哪个取决于 bool 参数)。然后,函数调用 3
将从填充的 Data
中检索结构的适当字段结构并用于填充它已传递的 map 。
这样,解析文件的代码就只在一处(3
)。从外面看,代码很好(两个不同的入口点返回适当的数据),但内部实现在我看来并不正确(使用结构作为一种方法的技巧,可以使用单一方法来潜在地填充两种不同且独立的对象类型)。
我想过使用继承,这样泛型方法接收一个指向公共(public)基类的指针,该基类有两个方法(add_model_data()
和 add_company_data()
)。它会根据 bool
调用一个或另一个参数。然而,这更加复杂和困惑,并且意味着通过让基类知道低类的方法来打破抽象,它容易出错等。
问题是,是否有可能以某种方式将解析逻辑保留在一个地方,但使用与 struct
不同(并且可以说更好)的方法?为了处理不同的文件?
最佳答案
std::variant
和 boost::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_upto
是 this 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/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!