Мне нужен обходной путь или хорошее решение для инициализации группы постоянных переменных класса в базе и подклассе
Проблема проста, я получил базовый класс с двумя конструкторами и теми же двумя конструкторами в подклассе
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) {}
};
Подкласс должен вызывать конструктор из BASE для инициализации переменных класса из BASE, после чего подкласс инициализирует остальные переменные
Пока все хорошо, но проблема в том, что оба конструктора из SUB делают одно и то же, за исключением вызова другого конструктора из BASE
Я хочу что-то подобное
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() {}
но это не работает, потому что «вызов делегирующего конструктора должен быть единственным инициализатором-членом» …
Перемещение всего за пределы списка инициализатора не работает, потому что это переменные класса const
Вы можете создать «конструктор пересылки» для вашего производного класса:
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) {}
};
Это примет произвольные аргументы и направит их на BASE
, Конечно, он будет компилироваться только при вызове с аргументами, которые действительны для BASE
, но это верно для каждого случая.
Если вы хотите / должны быть супер-правильными, вы можете обусловить конструктор с помощью SFINAE на что-то вроде std::is_constructible<BASE, T&&...>
, но я бы не стал беспокоиться.
К сожалению, это правила языка, если у вас есть делегирующий конструктор это должна быть единственная часть списка инициализатора.
Вам нужно обойти это ограничение, например, дублируя список инициализатора конструктора по умолчанию:
SUB(const int b) : BASE(b), c(b), d(c + 3) {}