Reputation: 4038
Is it possible in C++ somehow split constructor into multiple pieces in class body? Like in Scala or Kotlin? I need it for DSL written using C++ metaprogramming.
I have data members with non-trivial initialization sequence, and I want to specify initialization code together with members declaration.
Today I have:
class foo {
foo() {
// code to initialize a;
a.something();
a.other_thing()
// code to initialize b;
b.other_thing(a);
}
T a;
T b;
};
Instead I want to specify initialization code together with member declaration, something like:
class foo {
T a;
{
a.something();
a.other_thing()
}
T b;
{
b.other_thing(a);
}
};
I've found two solutions that I don't like. First is to pass std::function parameter to every type, so I can initialize data members like this:
class foo {
a{ [&](){
// initialization code
}};
};
Unfortunately this requires refactoring of all third-party libraries I use.
Second option is introducing a "dummy" data member just to execute lambda:
T a;
dummy_type a_init = [](&) { ... }
That can be hidden inside MACRO:
T a; INIT(a) { ... }
Everything is nice, but how can I create a zero-sized object in C++, so that each dummy initializer does not increase class size?
Upvotes: 0
Views: 447
Reputation: 385274
You can use a lambda without any external changes if you call it immediately:
class foo
{
foo()
: a([=]() {
T a;
a.something();
a.other_thing();
return a;
}())
, b([=]() {
T b;
b.other_thing(a);
return b;
}())
{}
T a;
T b;
};
Is it pretty? Hell no! But it should work, unless T
is hard/impossible to move/copy.
You can move the initialisers inline, too:
class foo
{
T a = [=]() {
T a;
a.something();
a.other_thing();
return a;
}();
T b = [=]() {
T b;
b.other_thing(a);
return b;
}();
};
Alternatively set up a factory function/type somewhere and just invoke that instead.
If you're really desperate, make the members unique_ptr
s and resort to dynamic allocation like in the olden days (which you can scatter throughout your constructor body however you like). Probably the easiest solution tbh.
class foo
{
public:
foo()
{
a = std::make_unique<T>();
a->something();
a->other_thing();
b = std::make_unique<T>();
b->other_thing(*a);
}
private:
std::unique_ptr<T> a;
std::unique_ptr<T> b;
};
Upvotes: 3