patterncppMinor
Vector of derived classes
Viewed 0 times
derivedvectorclasses
Problem
Everyone knows you can't put a
```
#pragma once
#include
#include
#include
template
class DerivedVector {
struct Block;
public:
using value_type = T;
using reference = T&;
using const_reference = T const&;
using pointer = T*;
using const_pointer = T const*;
private:
struct TypeInfo {
using deleter_t = void()(void);
deleter_t deleter;
using mover_t = void()(Block&, void);
mover_t mover;
};
template
struct TypeInfoImpl {
static_assert(std::is_destructible::value, "Derived class not destructible");
static_assert(std::is_move_constructible::value, "Derived class not move-constructible");
static_assert(std::is_base_of::value, "Class is not derived");
static_assert(sizeof(D) (p)->~D();
}
static void mover(Block& p, void* o) {
new (p.data()) D(std::move(*static_cast(o)));
}
static TypeInfo* get() {
static TypeInfo info{deleter, mover};
return &info;
}
};
struct Block {
using element_type = T;
TypeInfo* info = nullptr;
typename std::aligned_storage::type storage;
Block() = default;
template::type>::value>::type>
Block(D&& d) {
construct(std::forward(d));
}
Block(Block&& b) : info(b.info) {
if (info)
info->mover(*this, b.data());
}
Block& operator=(Block&& b) {
if (this == &b)
return *this;
destroy();
info = b.info;
info->mover(*this, b.data());
return *this;
}
Block(Block const& b) = delete;
void operator=(Block const&) = delete;
template
void construct(D&& d) {
using D_Val = typename std::remove_reference::type;
Derived in an std::vector. I decided to implement a collection which does allow you to do this:```
#pragma once
#include
#include
#include
template
class DerivedVector {
struct Block;
public:
using value_type = T;
using reference = T&;
using const_reference = T const&;
using pointer = T*;
using const_pointer = T const*;
private:
struct TypeInfo {
using deleter_t = void()(void);
deleter_t deleter;
using mover_t = void()(Block&, void);
mover_t mover;
};
template
struct TypeInfoImpl {
static_assert(std::is_destructible::value, "Derived class not destructible");
static_assert(std::is_move_constructible::value, "Derived class not move-constructible");
static_assert(std::is_base_of::value, "Class is not derived");
static_assert(sizeof(D) (p)->~D();
}
static void mover(Block& p, void* o) {
new (p.data()) D(std::move(*static_cast(o)));
}
static TypeInfo* get() {
static TypeInfo info{deleter, mover};
return &info;
}
};
struct Block {
using element_type = T;
TypeInfo* info = nullptr;
typename std::aligned_storage::type storage;
Block() = default;
template::type>::value>::type>
Block(D&& d) {
construct(std::forward(d));
}
Block(Block&& b) : info(b.info) {
if (info)
info->mover(*this, b.data());
}
Block& operator=(Block&& b) {
if (this == &b)
return *this;
destroy();
info = b.info;
info->mover(*this, b.data());
return *this;
}
Block(Block const& b) = delete;
void operator=(Block const&) = delete;
template
void construct(D&& d) {
using D_Val = typename std::remove_reference::type;
Solution
Interesting.
You should add
In terms of automatically determining blocksize, you can add a helper function like:
Users can then list the derived classes they want to use and use that to compute the block size.
You should add
template emplace_back(Args&&...).In terms of automatically determining blocksize, you can add a helper function like:
template
std::size_t get_max_size() {
return std::max({ sizeof(Args)... });
}Users can then list the derived classes they want to use and use that to compute the block size.
Code Snippets
template <typename... Args>
std::size_t get_max_size() {
return std::max({ sizeof(Args)... });
}Context
StackExchange Code Review Q#19275, answer score: 2
Revisions (0)
No revisions yet.