How can I aggregate init a struct that inherits from a virtual type?

Viewed 179

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?

1 Answers

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.

Related