class C {
public
T x;
};
Run Code Online (Sandbox Code Playgroud)
是否有一种优雅的方式让x的构造函数隐式地知道它构造的C的实例?
class TestRecordset: public Recordset {
public:
// The order of fields declarations specifies column index of the field.
// There is TestRecordset* pointer inside Field class,
// but it goes here indirectly so I don't have to
// re-type all the fields in the constructor initializer list.
Field<__int64> field1;
Field<wstring> field2;
Field<double> field3;
// have TestRecordset* pointer too so only name of parameter is specified
// in TestRecordset constructor
Param<wstring> param;
virtual string get_sql() {
return "SELECT 1, '1', NULL FROM test_table WHERE param=:PARAM";
}
// try & unlock are there because of my dirty tricks.
// I want to get rid of them.
TestRecordset(wstring param_value)
try : Recordset(open_database(L"test.db")), param("PARAM") {
param = param_value;
// I LOVE RAII but i cant use it here.
// Lock is set in Recordset constructor,
// not in TestRecordset constructor.
unlock(this);
fetch();
} catch(...) {
unlock(this);
throw;
}
};
我想澄清一下这个事实 - 它是工作代码的一部分.你可以用C++做到这一点.我只想以更好的方式做到这一点.
TestRecordset(wstring param_value): Recordset(open_database(L"test.db")), param("PARAM") { param = param_value; fetch(); }Run Code Online (Sandbox Code Playgroud)
TestRecordset(wstring param_value): Recordset(open_database(L"test.db")), param(this, "PARAM"), field1(this, 0), field2(this, 1), field3(this, 2) { ... }Run Code Online (Sandbox Code Playgroud)
这是多余,丑陋和不方便的.例如,如果我必须在SELECT中间添加新字段,我将不得不重写所有列号.您帖子上的一些注意事项:
不应该.对象不应该知道它们在哪里被使用才能工作.就x而言,它是T的一个实例.就是这样.根据它是C类的成员,D类的成员,自动,临时等,它的行为不同.
此外,即使T构造函数确实知道C的实例,C的实例也是不完整的,因为它当然还没有完成构造,因为它的成员还没有被构造.C++为你提供了很多机会射击自己,但是在另一个类的构造函数中提供一个不完整对象的引用并不是其中之一.
我能想到的唯一能够近似你的代码示例的是做类似的事情
#define INIT_FIELDS field1(this), field2(this), field3(this)
Run Code Online (Sandbox Code Playgroud)
紧接在字段列表之后,然后在初始化列表中使用INIT_FIELDS并#undef它.它仍然是重复,但至少它在一个地方.但是,这可能会让您的同事感到惊讶.
另一种确保不忘记字段的方法是从Field中删除零参数构造函数.同样,您仍然需要进行输入,但至少如果您忘记了编译器将捕获它的内容.我认为,初始化程序列表的非DRY特性是C++必须要使用的东西.