As per [dcl.init.aggr] I cannot aggregate init a type, if it has (among other things) virtual functions, which includes inheriting from a type with a virtual destructor. However, I'd like to avoid having to write a ton of boilerplate constructors.
MWE:
struct Base {
virtual ~Base() {}
};
struct Derived : Base {
int i;
};
int main() {
Derived d1{42}; // not allowed in this fashion
Derived d2{{},42}; // also not allowed
}
In my setting I have a lot of types like Derived
and they are all plain structs with a number of members (not necessarily trivial/pod) except for the fact that they have to inherit from Base
.
Is there a way to avoid having to write Derived(int i) : Base(), i(i) {}
constructors for all of them?
The one solution I could think of, is to exploit the fact that a struct without the inheritance above will gladly emit a default aggregate initialiser. So I compose that struct together with a templated wrapper type.
template <typename T>
struct BaseWrapper : Base, T {
BaseWrapper(T data) : Node(), T(data) {}
BaseWrapper() = delete;
BaseWrapper(BaseWrapper const&) = default;
BaseWrapper(BaseWrapper&&) = default;
BaseWrapper& operator=(BaseWrapper const&) = default;
BaseWrapper& operator=(BaseWrapper&&) = default;
static T const& cast(Base const& b) {
return static_cast<T const&>(static_cast<BaseWrapper<T> const&>(b));
}
static T& cast(Base& b) {
return static_cast<T&>(static_cast<BaseWrapper<T>&>(b));
}
};
And since I use the Derived
types as shared pointers, a small convenience function:
template <typename T, typename... Args>
inline std::shared_ptr<BaseWrapper<T>> make_bw(Args&&... args) {
return std::make_shared<BaseWrapper<T>>(T{std::forward<Args>(args)...});
}
Allows us to create objects without the need of a dedicated constructor inside the object:
struct Derived { // note the missing : Base
int i;
};
auto p = make_bw<Derived>(42);
This is a bit of a cheaty solution, so a proper answer would still be useful.