22class SharedReadablePtr final {
 
   23  static_assert(!std::is_const_v<T>,
 
   24                "SharedReadablePtr already adds `const` to `T`");
 
   25  static_assert(!std::is_reference_v<T>,
 
   26                "SharedReadablePtr does not work with references");
 
   29  using Base = std::shared_ptr<
const T>;
 
   30  using MutableBase = std::shared_ptr<T>;
 
   31  using Weak = 
typename Base::weak_type;
 
   32  using Unique = std::unique_ptr<
const T>;
 
   33  using element_type = T;
 
   35  SharedReadablePtr(
const SharedReadablePtr& ptr) 
noexcept = 
default;
 
   36  SharedReadablePtr(SharedReadablePtr&& ptr) 
noexcept = 
default;
 
   38  constexpr SharedReadablePtr(std::nullptr_t) 
noexcept : base_(
nullptr) {}
 
   40  SharedReadablePtr& operator=(
const SharedReadablePtr& ptr) 
noexcept = 
default;
 
   41  SharedReadablePtr& operator=(SharedReadablePtr&& ptr) 
noexcept = 
default;
 
   43  SharedReadablePtr(
const Base& ptr) 
noexcept : base_(ptr) {}
 
   45  SharedReadablePtr(Base&& ptr) 
noexcept : base_(std::move(ptr)) {}
 
   47  SharedReadablePtr(
const MutableBase& ptr) 
noexcept : base_(ptr) {}
 
   49  SharedReadablePtr(MutableBase&& ptr) 
noexcept : base_(std::move(ptr)) {}
 
   51  SharedReadablePtr(Unique&& ptr) 
noexcept : base_(std::move(ptr)) {}
 
   53  SharedReadablePtr& operator=(
const Base& ptr) 
noexcept {
 
   58  SharedReadablePtr& operator=(Base&& ptr) 
noexcept {
 
   59    base_ = std::move(ptr);
 
   63  SharedReadablePtr& operator=(
const MutableBase& ptr) 
noexcept {
 
   68  SharedReadablePtr& operator=(MutableBase&& ptr) 
noexcept {
 
   69    base_ = std::move(ptr);
 
   73  SharedReadablePtr& operator=(std::nullptr_t) 
noexcept {
 
   78  const T* Get() 
const& 
noexcept { 
return base_.get(); }
 
   80  const T& operator*() 
const& 
noexcept { 
return *base_; }
 
   82  const T& operator*() && { ReportMisuse(); }
 
   84  const T* operator->() 
const& 
noexcept { 
return base_.get(); }
 
   86  const T* operator->() && { ReportMisuse(); }
 
   88  operator 
const Base&() 
const& 
noexcept { 
return base_; }
 
   90  operator 
const Base&() && { ReportMisuse(); }
 
   92  operator Weak() 
const& 
noexcept { 
return base_; }
 
   94  operator Weak() && { ReportMisuse(); }
 
   96  explicit operator 
bool() 
const noexcept { 
return !!base_; }
 
   98  bool operator==(
const SharedReadablePtr<T>& other) 
const {
 
   99    return base_ == other.base_;
 
  102  bool operator!=(
const SharedReadablePtr<T>& other) 
const {
 
  103    return !(*
this == other);
 
  106  void Reset() 
noexcept { base_.reset(); }
 
  109  [[noreturn]] 
static void ReportMisuse() {
 
  110    static_assert(!
sizeof(T), 
"keep the pointer before using, please");
 
  117bool operator==(
const SharedReadablePtr<T>& ptr, std::nullptr_t) {
 
  122bool operator==(std::nullptr_t, 
const SharedReadablePtr<T>& ptr) {
 
  127bool operator!=(
const SharedReadablePtr<T>& ptr, std::nullptr_t) {
 
  128  return !(ptr == 
nullptr);
 
  132bool operator!=(std::nullptr_t, 
const SharedReadablePtr<T>& ptr) {
 
  133  return !(
nullptr == ptr);
 
  136template <
typename T, 
typename... Args>
 
  137SharedReadablePtr<T> MakeSharedReadable(Args&&... args) {
 
  138  return SharedReadablePtr<T>{std::make_shared<T>(std::forward<Args>(args)...)};