Единственное решение, о котором я мог подумать, - это использовать тот факт, что структура без наследования, указанного выше, с радостью выдаст инициализатор агрегата по умолчанию. Поэтому я сочиняю эту структуру вместе с шаблонным типом оболочки.
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));
}
};
И так как я использую типы Derived
в качестве общих указателей, небольшая вспомогательная функция:
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)...});
}
Позволяет нам создавать объекты без необходимости использования специального конструктора внутри объекта:
struct Derived { // note the missing : Base
int i;
};
auto p = make_bw<Derived>(42);
Это немного обманчивое решение, поэтому правильный ответ все равно будет полезен.