【发布时间】:2020-02-27 01:43:56
【问题描述】:
我希望我所有的数据保存和加载都通过相同的功能来减少出现错误的机会。为此,我使用了很多模板(以及很多函数重载)。它起作用了,我的代码现在更干净了,但我无法使用const 进行保存(因为它通过与加载器相同的功能,其中数据保持非常量)。
我想正确使用const,所以这里尝试让一个简单的版本工作,其中数据(在本例中为std::vector)对于std::ifstream和@987654326来说是非常量的@否则:
#include <iostream>
#include <fstream>
#include <vector>
template <class Foo>
void Overload(const Foo & foo)
{
std::cout << "went to const" << std::endl;
}
template <class Foo>
void Overload(Foo & foo)
{
std::cout << "went to non-const" << std::endl;
}
template <class StreamType, typename... Arguments>
void ReadOrWrite (
/* for 1st argument */ StreamType & filestream,
/* type for 2nd argument */ typename std::conditional<
/* if */ std::is_same<StreamType, std::ifstream>::value,
/* then */ std::vector<Arguments...>,
/* else */ const std::vector <Arguments...>
>::type
/*2nd argument name */ & vector
)
{
Overload(vector);
}
int main ()
{
std::ofstream output_filestream;
std::ifstream intput_filestream;
std::vector<int> vector;
ReadOrWrite(output_filestream, vector);
ReadOrWrite(intput_filestream, vector);
return 0;
}
我知道如果我编辑对此的函数调用,它将正确编译/运行:
ReadOrWrite<std::ofstream, int>(output_filestream, vector);
ReadOrWrite<std::ifstream, int>(intput_filestream, vector);
但我不希望函数的用户在函数调用期间需要列出类型。
有没有一种干净的方法来做我建议的事情?
编辑
我的动机的合法性似乎存在疑问。
我没有彻底解释我的动机,因为它不是太简单(也不是太复杂),我尊重读者的时间。
我给出的示例是我无法解决的最简单的部分——“重载”函数只是为了看看它是否有效。
但是看来我的解释不够引起了混乱,所以我会解释一下:
我制作了一个小型库来处理一般情况下的数据保存和加载。它通过使用以下接口成功地允许用户的类具有简单的保存/加载方法:
class SomeClass
{
public:
template <class StreamType>
void SaveOrLoad(StreamType & filestream)
{
saveload::SaveToOrLoadFromFile(filestream,
data_1_,
data_2_,
/* ..., */
data_n_,
);
}
void SaveToFile (const std::string & filename)
{
std::ofstream output_filestream(filename, std::ios::binary);
// file handling
SaveOrLoad(output_filestream);
}
void LoadFromFile (const std::string & filename)
{
std::ifstream input_filestream(ptf::problem_input_file, std::ios::binary);
// file handling
SaveOrLoad(input_filestream);
}
};
该库处理所有基本数据类型、STL 容器和任何其他使用正确SaveOrLoad(StreamType &) 接口的容器,包括所有容器的保存和调整大小。该库已强制所有保存和加载都通过相同的确定性函数,因此完全消除了涉及保存/加载不匹配的错误的可能性(除非用户滥用库的简单界面)。
我的图书馆遇到的问题 - 以及我提出问题的原因 - 是理论上的问题,因为我目前不需要它:SaveToFile 方法应该可以是 const。
【问题讨论】:
-
就目前而言,
std::conditional中的内容是非推断上下文,这就是为什么不会为您推断Arguments的原因。我将在两者之间添加另一个级别:仅将T作为第二个参数的函数,并且根据T是否为const,调用单独的ReadOrWrite函数(嗯,Read和Write)。在 C++11 中,这比我们在较新版本中使用的constexpr要麻烦一些,但可行。我还看到了“我通过同一个函数进行读写”的大危险信号——这几乎肯定违反了单一责任原则...... -
"...以减少出现错误的机会。为此,我使用了很多模板"。这让我发笑。我认为你实际上是在创造一个上帝功能:一个可以做任何事情的功能。 That is considered an anti pattern
-
我个人会编写单独的读写函数。他们做不同的事情,所以他们应该分开。这让您可以轻松地将
const应用到 write 函数中。 -
我建议您从标准库及其处理容器的方式中汲取灵感:改为传递迭代器对。这通常会简化事情,并使您的功能更灵活地启动(因为它们可以处理其他容器和部分范围)。
-
明确地说,我在一个数据库上使用了这个,其中嵌套数据类型的大型问题实例必须以与加载时完全相同的方式保存,否则您最终会得到非常严重错误加载,经常导致崩溃。每个类类型中的数据列表都很长,将加载和保存分开是一个非常糟糕的设计。
标签: c++ oop c++11 vector constants