Is there non-static block in C++?
If no, how to emulate it elegantly?
I want to replace something like :-
class C{
public: void ini(){/* some code */}
};
class D{
std::vector<C*> regis; //will ini(); later
public: C field1;
public: C field2;
public: C field3; //whenever I add a new field, I have to ... #1
public: D(){
regis.push_back(&field1);
regis.push_back(&field2);
regis.push_back(&field3); //#1 ... also add a line here
}
public: void ini(){
for(auto ele:regis){
ele->ini();
}
}
};
with :-
class D{
std::vector<C*> regis;
public: C field1;{regis.push_back(&field1);}//less error-prone (because it is on-site)
public: C field2;{regis.push_back(&field2);}
public: C field3;{regis.push_back(&field3);}
public: D(){ } //<-- empty
public: void ini(){
for(auto ele:regis){
ele->ini();
}
}
};
I found many questions related to static-block in C++, but didn't found any one about non-static-block.
To make it easy to answer, here is a full code.
It can be done using X-MACRO (wiki link), but I am trying to avoid it.
In real case, fieldX
can has any types that derived from a certain C
.
I consider another bad workaround :-
class D{
std::vector<C*> regis;
char f(C& c){ regis.push_back(&c); return 42;}
public: C field1; char dummyWaste1=f(field1);
public: C field2; char dummyWaste2=f(field2);
public: C field3; char dummyWaste3=f(field3);
skypjack's answer is very useful, but I am curious to find out more alternatives.
The final objective is to emulate general non-static block that has more variety.
In other words, it would be nice if new solution can solve this :-
class D{
int field1=5;
{ do something very custom; /* may access field1 which must = 5 */}
//^ have to be executed after "field1=5;" but before "field2=7"
int field2=7;
int field3=8;
{ do something very custom ; /* e.g. "field1=field2+field3" */}
//^ have to be executed after "field3=8;"
};
without wasting 1 char
(or more - for alignment) for each block.
how to emulate it elegantly?
You can initialize regis
directly:
std::vector<C*> regis = { &field1, &field2, &field3 };
That is, define your class as:
class D{
public:
C field1;
C field2;
C field3;
void ini(){
for(auto ele:regis){
ele->ini();
}
}
private:
std::vector<C*> regis = { &field1, &field2, &field3 };
};
Otherwise, if you can add a constructor to C
, revert the logic and have it adding itself to the vector:
#include<vector>
struct C {
C(std::vector<C*> &vec) {
vec.push_back(this);
// ...
}
void ini() {}
};
class D{
std::vector<C*> regis{};
public:
C field1 = regis;
C field2 = regis;
C field3 = regis;
void ini(){
for(auto ele:regis){
ele->ini();
}
}
};
int main() { D d{}; d.ini(); }
------ EDIT ------
As requested in the comments:
C
is a holy class for me. Is it possible to not hackC
?
Here is a possible alternative that doesn't require you to modify C
:
#include<vector>
struct C {
void ini() {}
};
struct Wrapper {
Wrapper(std::vector<C*> &vec) {
vec.push_back(*this);
// ...
}
operator C *() { return &c; }
private:
C c;
};
class D{
std::vector<C*> regis{};
public:
Wrapper field1{regis};
Wrapper field2{regis};
Wrapper field3{regis};
void ini(){
for(auto ele:regis){
ele->ini();
}
}
};
int main() { D d{}; d.ini(); }