我讨厌为我的c ++程序编写配置数据类:愚蠢的小数据类,带有一些标准函数:print()和scan(),有时是二进制read()和write(),通常是bind()将每个数据成员绑定到boost :: program_options :: options_description(这样我就可以从命令行或配置文件中设置配置数据)。
我已经初步尝试使用模板来减少编写这些课程的单调性,我想知道是否有人可以告诉我,如果我在重新投入时间之前重新发明轮子。我也想知道是否有任何人欣赏我尝试做的事情(而不是认为我完全疯了。)
基本思想是,不是写print(),scan(),read(),write()等,而是继承Print,Scan,Read和Write(我会调用服务类)因为缺乏一个更好的名称,它分别为我(通过双重调度)实现前面提到的方法,每个方法都按顺序打印,扫描,读取或写入每个数据成员的单调任务。当然,这些继承的方法执行速度比手工编写的方法要慢,但如果打印或扫描配置数据需要几微秒的时间,我真的不在乎。更重要的是,这些继承的类都没有添加数据(因此没有额外的开销来实例化或复制我的配置类的实例)。
我必须为一堂课做三件事才能使它全部运转:
然后我还要写一个" Class"的部分模板专门化。描述我班级的班级。最后,必须将每个此类的实例加载到每个服务类(使用它们来确定如何处理类实例)。
下面是一个main.cpp,希望能让你感受到我正在做的事情。让我知道你的想法。
#include "Print.hpp"
#include "Scan.hpp"
#include "Write.hpp"
#include "Read.hpp"
using namespace std;
class MyConfig : public Print, public Scan, public Write, public Read {
public:
const string className() const { return "MyConfig"; }
const int& i() const { return _i; }
const string& s() const { return _s; }
void i(int value) { _i = value; }
void s(const string& value) { _s = value; }
private:
int _i;
string _s;
// The Scan and Read interfaces require a way to write the set
// directly, hence these getter methods that return non-const
// references. I make these private, then define the friend below
// so Scan and Read can get at them.
//
int& i() { return _i; }
string& s() { return _s; }
template<class C, class P> friend class Class;
};
// Meta-class describing the members of class MyConfig and
// how to get at them.
//
template<class P>
class Class<MyConfig,P> : public ClassImpl<MyConfig,P> {
public:
Class() : ClassImpl<MyConfig,P>("MyConfig") {
*this->template genMember<int> ("i", &MyConfig::i, &MyConfig::i);
*this->template genMember<string>("s", &MyConfig::s, &MyConfig::s);
}
};
int main(int argc, char** argv) {
try {
// Each interface class is loaded with Class objects describing
// user-data classes that use the interface.
//
Print::addClass<MyConfig>();
Scan ::addClass<MyConfig>();
Write::addClass<MyConfig>();
Read ::addClass<MyConfig>();
MyConfig x;
x.i(3);
x.s("abc");
cout << "Printing config:\n" << x; // print x
cout << "Scanning config:" << endl;
cin >> x; // scan x
cout << "The scanned config was:" << endl;
cout << x; // print x again
cout << "Writing config to file." << endl;
ofstream ofs;
ofs.exceptions(ios::failbit | ios::badbit);
ofs.open("testfile", ios::out | ios::binary);
x.write(ofs); // write x to file in binary format
ofs.close();
cout << "Reading config back from file." << endl;
MyConfig x2;
ifstream ifs;
ifs.exceptions(ios::failbit | ios::badbit | ios::eofbit);
ifs.open("testfile", ios::in | ios::binary);
x2.read(ifs); // read x from file in binary format
ifs.close();
cout << x2;
}
catch(const exception& x) {
cerr << argv[0] << ": " << x.what() << endl;
return 1;
}
return 0;
}
节目输出:
matt@dworkin:$ ./a.out
Printing config:
i = 3
s = abc
Scanning config:
i=4
s=xyz
The scanned config was:
i = 4
s = xyz
Writing config to file.
Reading config back from file.
i = 4
s = xyz