Skip to content

Instantly share code, notes, and snippets.

@alexanderchuranov
Created July 10, 2024 01:38
Show Gist options
  • Select an option

  • Save alexanderchuranov/efce7b181ffce7ebbcd33d64554f534f to your computer and use it in GitHub Desktop.

Select an option

Save alexanderchuranov/efce7b181ffce7ebbcd33d64554f534f to your computer and use it in GitHub Desktop.
The container/view in C++20
#include <cassert>
#include <string>
#include <type_traits>
#include <utility>
template <typename T>
class View {
public:
View() = default;
explicit View(T* p) : p_(p) { }
View(View const&) = default;
template <typename U>
View(View<U> const& source)
: p_(source.p_) { }
bool empty() const { return p_ == nullptr; }
T* data() const { return p_; }
T& access() const { return *p_; }
View& operator=(View const&) = default;
bool operator==(View const& rhs) const {
return *p_ == *rhs.p_;
}
bool operator!=(View const&) const = default;
bool same_view(View const& rhs) const {
return this->p_ == rhs.p_;
}
private:
template <typename U>
friend class View;
T* p_ = nullptr;
};
template <typename T>
class Container {
public:
Container() = default;
Container(Container const&) = default;
Container(Container&& src) {
std::swap(value_, src.value_);
}
template <typename U>
Container(Container<U> const& src) : value_{src.value_} { }
explicit Container(T const& value) : value_{value} { }
explicit Container(View<T> const& src) : value_(src.access()) { }
template <typename U>
explicit Container(View<U> const& src): value_(src.access()) { }
View<T> const view() {
return View<T>{&value_};
}
View<T const> const view() const {
return View<T const>{&value_};
}
Container& operator=(Container const&) = default;
Container& operator=(Container&& src) {
std::swap(value_, src.value_);
return *this;
}
bool operator==(Container const&) const = default;
bool operator!=(Container const& rhs) const = default;
template <typename U>
bool operator==(Container<U> const& src) const {
return value_ == src.value_;
}
private:
template <typename U>
friend class Container;
T value_;
};
void view_assertions() {
int a = 3;
assert(View<int>{}.empty());
assert(View{&a}.access() == 3);
assert(View{&a}.data() == &a);
View source{&a};
View copy1{source};
View<int> copy2;
copy2 = source;
assert(copy1.data() == &a);
assert(copy2.data() == &a);
View<int> writable_source{&a};
View<int const> readable_view1{writable_source};
View<int const> readable_view2;
readable_view2 = writable_source;
assert(readable_view1.data() == &a);
assert(readable_view2.data() == &a);
View<int const> readable_source{&a};
View<int> writable_view2;
//
// error: cannot initialize a member subobject of type 'int *'
// with an lvalue of type 'const int *const'
//
// View<int> writable_view1{readable_source};
// writable_view2 = readable_source;
int b = 3;
int c = 5;
assert(View{&b} == View{&a});
assert(not View{&b}.same_view(View{&a}));
assert(not(View{&b} != View{&a}));
assert(View{&b} != View{&c});
assert(not(View{&b} == View{&c}));
assert(View{&a}.same_view(View{&a}));
int x = 10;
View const writable{&x}; // View<T> const where 'T' is non-const.
assert(writable.access() == 10);
writable.access() = 17;
assert(writable.access() == 17);
int y = 11;
View<int const> non_writable{&y}; // View<T const> where
// 'non_writable' is non-const
assert(non_writable.access() == 11);
// error: cannot assign to return value because function 'access'
// returns a const value
// non_writable.access() = 33;
}
void container_assertions() {
assert(Container<int>{}.view().access() == 0);
Container<int> a{3};
Container<int> copy{a};
Container<int> copy2{a.view()};
assert(copy.view().access() == 3);
assert(not copy.view().same_view(a.view()));
assert(copy2.view().access() == 3);
assert(not copy2.view().same_view(a.view()));
Container<short int> b{7};
Container<int> copy3{b};
Container<int> copy4{b.view()};
assert(copy3.view().access() == 7);
assert(static_cast<void*>(copy3.view().data())
!= static_cast<void*>(b.view().data()));
assert(copy4.view().access() == 7);
assert(static_cast<void*>(copy4.view().data())
!= static_cast<void*>(b.view().data()));
Container<int> e;
e = a;
assert(e.view().access() == 3);
e = b;
assert(e.view().access() == 7);
assert(copy == a);
assert(not(copy != a));
assert(not(a == b));
assert(a != b);
Container<std::string> orig1{"abcdefgijklmnopqrstuvwxyz"};
Container<std::string> receiver1{std::move(orig1)};
Container<std::string> orig2{"zyxwvutsrqponmlkjigfedcba"};
Container<std::string> receiver2;
receiver2 = std::move(orig2);
assert(receiver1.view().access() == "abcdefgijklmnopqrstuvwxyz");
assert(orig1.view().access() == "");
assert(orig1 != receiver1);
assert(receiver2.view().access() == "zyxwvutsrqponmlkjigfedcba");
assert(orig2.view().access() == "");
assert(orig2 != receiver2);
Container<int> writable{11};
assert(writable.view().access() == 11);
writable.view().access() = 17;
assert(writable.view().access() == 17);
Container<int> const non_writable{5};
assert(non_writable.view().access() == 5);
// error: cannot assign to return value because function 'access'
// returns a const value
// non_writable.view().access() = 33;
}
int main() {
view_assertions();
container_assertions();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment