I need a workaround or a nice solution for initializing a bunch of constant class variables in base and subclass
The problem is simple, I got a baseclass with two constructor and the same two constructor in the subclass
class BASE {
int a;
int func(float x) { // just a dummy to show that this function
return (a = (int) x) + 2; // modifies a
}
public:
const int b;
BASE(const int b) : b(b) {} // doesn't use a
BASE(const float x) : a(0), b(func(x)) {}
};
struct SUB: public BASE {
const int c;
const int d;
SUB(const int b) : BASE(b), c(b), d(c + 3) {}
SUB(const float x) : BASE(x), c(b), d(c + 3) {}
};
The subclass needs to call the constructor from BASE to initialize the class variables from BASE after that the sub class initialize the remaining variables
So far so good but the problem is that both constructor from SUB do the exactly same except calling a different constructor from BASE
I want something like that
SUB() : c(b), d(c + 3) {} // BASE() needs to be defined
SUB(const int b) : BASE(b), SUB() {}
SUB(const float x) : BASE(x), SUB() {}
but that doesn't work because "a call to a delegating constructor shall be the only member-initializer" ...
Moving everything outside the initializer list doesn't work because these are const class variables
You can create a "forwarding constructor" for your derived class:
struct SUB: public BASE {
const int c;
const int d;
template <class... T>
SUB(T&&... a) : BASE(std::forward<T>(a)...), c(b), d(c + 3) {}
};
This will accept arbitrary arguments and forward them on to BASE
. Of course, it will only compile when called with arguments which are valid for BASE
, but that holds for every case.
If you want/need to be super-correct, you can condition the constructor using SFINAE on somethin like std::is_constructible<BASE, T&&...>
, but I wouldn't bother.