*
So kann man das ganz ohne Casts nutzen, wenn man schon Delegation nutzt.
#include <memory>
#include <cstddef>
#include <iterator>
template <typename T, class Allocator = std::allocator<T>>
class SimpleStorage {
public:
using allocator_type = Allocator;
using alloc_traits = typename std::allocator_traits<allocator_type>;
using size_type = typename alloc_traits::size_type;
allocator_type alloc;
size_type c;
T* p;
~SimpleStorage () {alloc.deallocate(p,c);}
SimpleStorage (const size_type capacity, allocator_type& a) : c(capacity), p(alloc.allocate(c)) {}
SimpleStorage (const size_type capacity) : alloc({}), c(capacity), p(alloc.allocate(c)) {}
SimpleStorage (const SimpleStorage&) = delete;
SimpleStorage (SimpleStorage&&) = delete;
SimpleStorage& operator= (const SimpleStorage&) = delete;
SimpleStorage& operator= (SimpleStorage&&) = delete;
};
template<typename T>
class vector_t {
public:
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = T const&;
using size_type = std::size_t;
private:
size_type data_size;
std::unique_ptr<SimpleStorage<T>> storage;
public:
pointer data() noexcept {return std::launder(storage->p);}
const_pointer data() const noexcept {return std::launder(storage->p);}
explicit vector_t(std::size_t size = 0, value_type const &value = value_type{})
: data_size(size), storage(std::make_unique<SimpleStorage<T>>(data_size))
{
std::uninitialized_fill_n(data(), data_size, value);
}
vector_t(vector_t<T> const &other) : vector_t(other.begin(), other.end()) {}
vector_t(std::initializer_list<value_type> ilist) : vector_t(ilist.begin(), ilist.end()) {}
template <typename ForwardIt>
vector_t(ForwardIt first, ForwardIt last)
: data_size(std::distance(first, last)), storage(std::make_unique<SimpleStorage<T>>(data_size))
{
std::uninitialized_copy_n(first, data_size, storage->p);
}
friend void swap(vector_t<T> &a, vector_t<T> &b) noexcept {
using std::swap;
swap(a.data_size, b.data_size);
swap(a.storage, b.storage);
}
vector_t& operator=(vector_t<T> other) noexcept {
swap(*this, other);
return *this;
}
~vector_t() {
std::destroy_n(data(), size());
}
pointer begin() noexcept {return data();}
pointer end() noexcept {return data() + size();}
const_pointer begin() const noexcept {return data();}
const_pointer end() const noexcept {return data() + size();}
size_type size() const noexcept { return data_size; }
size_type capacity() const noexcept { return storage->c; }
reference operator[](size_type index) { return data()[index]; }
const_reference operator[](size_type index) const { return data()[index]; }
private:
reference checked_access(size_type index) {
if (data_size <= index)
throw std::out_of_range{ "vector_t::at(" + std::to_string(index) + ")" };
return operator[](index);
}
public:
reference at(size_type index) { return checked_access(index); }
const_reference at(size_type index) const { return const_cast<vector_t*>(this)->checked_access(index); }
};
#include <string>
#include <iostream>
int main() {
vector_t<std::string> vec{"asdf", "Swordfish", "blub"};
vector_t vec2 = vec;
for (auto& s : vec2) std::cout << s << std::endl;
}