ptrs
template <class F>
struct converter {explicit converter(F f) noexcept : f_(std::move(f)) {}converter(const converter&) = delete;template <class T>operator T() && noexcept(std::is_nothrow_invocable_r_v<T, F, std::in_place_type_t<T>>)requires(std::is_invocable_r_v<T, F, std::in_place_type_t<T>>){return std::move(f_)(std::in_place_type<T>);}private:F f_;
};
隐式转换到 T
注意有一个 && 限定,因此只有 converter&& 类型才能调用
template <class LR, class CLR, class RR, class CRR>
class observer_ptr {
public:explicit observer_ptr(LR lr) : lr_(lr) {}observer_ptr(const observer_ptr&) = default;auto operator->() noexcept { return std::addressof(lr_); }auto operator->() const noexcept {return std::addressof(static_cast<CLR>(lr_));}LR operator*() & noexcept { return static_cast<LR>(lr_); }CLR operator*() const& noexcept { return static_cast<CLR>(lr_); }RR operator*() && noexcept { return static_cast<RR>(lr_); }CRR operator*() const&& noexcept { return static_cast<CRR>(lr_); }private:LR lr_;
};
相当抽象的重载
template <class T, class Alloc, class... Args>
T* allocate(const Alloc& alloc, Args&&... args) {auto al =typename std::allocator_traits<Alloc>::template rebind_alloc<T>(alloc);auto deleter = [&](T* ptr) { al.deallocate(ptr, 1); };std::unique_ptr<T, decltype(deleter)> result{al.allocate(1), deleter};std::construct_at(result.get(), std::forward<Args>(args)...);return result.release();
}
template <class Alloc, class T>
void deallocate(const Alloc& alloc, T* ptr) {auto al =typename std::allocator_traits<Alloc>::template rebind_alloc<T>(alloc);std::destroy_at(ptr);al.deallocate(ptr, 1);
}
template <class Alloc>
struct alloc_aware {explicit alloc_aware(const Alloc& alloc) noexcept : alloc(alloc) {}alloc_aware(const alloc_aware&) noexcept = default;[[PROD_NO_UNIQUE_ADDRESS_ATTRIBUTE]]Alloc alloc;
};
template <class T>
class indirect_ptr {
public:explicit indirect_ptr(T* ptr) noexcept : ptr_(ptr) {}auto operator->() noexcept { return std::addressof(**ptr_); }auto operator->() const noexcept { return std::addressof(**ptr_); }decltype(auto) operator*() & noexcept { return **ptr_; }decltype(auto) operator*() const& noexcept { return *std::as_const(*ptr_); }decltype(auto) operator*() && noexcept { return *std::move(*ptr_); }decltype(auto) operator*() const&& noexcept {return *std::move(std::as_const(*ptr_));}protected:T* ptr_;
};template <class T, class Alloc>
class PRO4D_ENFORCE_EBO allocated_ptr PROD_TR_IF_ELIGIBLE: private alloc_aware<Alloc>,public indirect_ptr<inplace_ptr<T>> {
public:template <class... Args>allocated_ptr(const Alloc& alloc, Args&&... args): alloc_aware<Alloc>(alloc),indirect_ptr<inplace_ptr<T>>(allocate<inplace_ptr<T>>(this->alloc, std::in_place, std::forward<Args>(args)...)) {}allocated_ptr(const allocated_ptr& rhs)requires(std::is_copy_constructible_v<T>): alloc_aware<Alloc>(rhs),indirect_ptr<inplace_ptr<T>>(allocate<inplace_ptr<T>>(this->alloc, std::in_place, *rhs)) {}allocated_ptr(allocated_ptr&& rhs) = delete;~allocated_ptr() noexcept(std::is_nothrow_destructible_v<T>) {deallocate(this->alloc, this->ptr_);}
};
看起来像是手写了一个内存池
template <class T, class Alloc>
struct PRO4D_ENFORCE_EBO compact_ptr_storage : alloc_aware<Alloc>,inplace_ptr<T> {template <class... Args>explicit compact_ptr_storage(const Alloc& alloc, Args&&... args): alloc_aware<Alloc>(alloc),inplace_ptr<T>(std::in_place, std::forward<Args>(args)...) {}
};
template <class T, class Alloc>
class compact_ptr PROD_TR_IF_ELIGIBLE: public indirect_ptr<compact_ptr_storage<T, Alloc>> {using Storage = compact_ptr_storage<T, Alloc>;public:template <class... Args>compact_ptr(const Alloc& alloc, Args&&... args): indirect_ptr<Storage>(allocate<Storage>(alloc, alloc, std::forward<Args>(args)...)) {}compact_ptr(const compact_ptr& rhs)requires(std::is_copy_constructible_v<T>): indirect_ptr<Storage>(allocate<Storage>(rhs.ptr_->alloc, rhs.ptr_->alloc, *rhs)) {}compact_ptr(compact_ptr&& rhs) = delete;~compact_ptr() noexcept(std::is_nothrow_destructible_v<T>) {deallocate(this->ptr_->alloc, this->ptr_);}
};struct shared_compact_ptr_storage_base {std::atomic_long ref_count = 1;
};
template <class T, class Alloc>
struct PRO4D_ENFORCE_EBO shared_compact_ptr_storage: shared_compact_ptr_storage_base,alloc_aware<Alloc>,inplace_ptr<T> {template <class... Args>explicit shared_compact_ptr_storage(const Alloc& alloc, Args&&... args): alloc_aware<Alloc>(alloc),inplace_ptr<T>(std::in_place, std::forward<Args>(args)...) {}
};
template <class T, class Alloc>
class shared_compact_ptr PROD_TR_IF_ELIGIBLE: public indirect_ptr<shared_compact_ptr_storage<T, Alloc>> {using Storage = shared_compact_ptr_storage<T, Alloc>;public:template <class... Args>shared_compact_ptr(const Alloc& alloc, Args&&... args): indirect_ptr<Storage>(allocate<Storage>(alloc, alloc, std::forward<Args>(args)...)) {}shared_compact_ptr(const shared_compact_ptr& rhs) noexcept: indirect_ptr<Storage>(rhs.ptr_) {this->ptr_->ref_count.fetch_add(1, std::memory_order::relaxed);}shared_compact_ptr(shared_compact_ptr&& rhs) = delete;~shared_compact_ptr() noexcept(std::is_nothrow_destructible_v<T>) {if (this->ptr_->ref_count.fetch_sub(1, std::memory_order::acq_rel) == 1) {deallocate(this->ptr_->alloc, this->ptr_);}}
};struct strong_weak_compact_ptr_storage_base {std::atomic_long strong_count = 1, weak_count = 1;
};
template <class T, class Alloc>
struct strong_weak_compact_ptr_storage : strong_weak_compact_ptr_storage_base,alloc_aware<Alloc> {template <class... Args>explicit strong_weak_compact_ptr_storage(const Alloc& alloc, Args&&... args): alloc_aware<Alloc>(alloc) {std::construct_at(reinterpret_cast<T*>(&value),std::forward<Args>(args)...);}alignas(alignof(T)) std::byte value[sizeof(T)];
};
template <class T, class Alloc>
class weak_compact_ptr;
template <class T, class Alloc>
class strong_compact_ptr PROD_TR_IF_ELIGIBLE: public indirect_ptr<strong_weak_compact_ptr_storage<T, Alloc>> {using Storage = strong_weak_compact_ptr_storage<T, Alloc>;public:explicit strong_compact_ptr(Storage* ptr) noexcept: indirect_ptr<Storage>(ptr) {}template <class... Args>strong_compact_ptr(const Alloc& alloc, Args&&... args): indirect_ptr<Storage>(allocate<Storage>(alloc, alloc, std::forward<Args>(args)...)) {}strong_compact_ptr(const strong_compact_ptr& rhs) noexcept: indirect_ptr<Storage>(rhs.ptr_) {this->ptr_->strong_count.fetch_add(1, std::memory_order::relaxed);}strong_compact_ptr(strong_compact_ptr&& rhs) = delete;~strong_compact_ptr() noexcept(std::is_nothrow_destructible_v<T>) {if (this->ptr_->strong_count.fetch_sub(1, std::memory_order::acq_rel) ==1) {std::destroy_at(operator->());if (this->ptr_->weak_count.fetch_sub(1u, std::memory_order::release) ==1) {deallocate(this->ptr_->alloc, this->ptr_);}}}auto get_weak() const noexcept {return converter{[ptr = this->ptr_]<class F>(std::in_place_type_t<proxy<F>>) noexcept -> proxy<F> {ptr->weak_count.fetch_add(1, std::memory_order::relaxed);return proxy<F>{std::in_place_type<weak_compact_ptr<T, Alloc>>, ptr};}};}T* operator->() noexcept {return std::launder(reinterpret_cast<T*>(&this->ptr_->value));}const T* operator->() const noexcept {return std::launder(reinterpret_cast<const T*>(&this->ptr_->value));}T& operator*() & noexcept { return *operator->(); }const T& operator*() const& noexcept { return *operator->(); }T&& operator*() && noexcept { return std::move(*operator->()); }const T&& operator*() const&& noexcept { return std::move(*operator->()); }
};
template <class T, class Alloc>
class weak_compact_ptr PROD_TR_IF_ELIGIBLE {
public:explicit weak_compact_ptr(strong_weak_compact_ptr_storage<T, Alloc>* ptr) noexcept: ptr_(ptr) {}weak_compact_ptr(const strong_compact_ptr<T, Alloc>& rhs) noexcept: ptr_(rhs.ptr_) {ptr_->weak_count.fetch_add(1, std::memory_order::relaxed);}weak_compact_ptr(const weak_compact_ptr& rhs) noexcept : ptr_(rhs.ptr_) {ptr_->weak_count.fetch_add(1, std::memory_order::relaxed);}weak_compact_ptr(weak_compact_ptr&& rhs) = delete;~weak_compact_ptr() noexcept {if (ptr_->weak_count.fetch_sub(1u, std::memory_order::acq_rel) == 1) {deallocate(ptr_->alloc, ptr_);}}auto lock() const noexcept {return converter{[ptr = this->ptr_]<class F>(std::in_place_type_t<proxy<F>>) noexcept -> proxy<F> {long ref_count = ptr->strong_count.load(std::memory_order::relaxed);do {if (ref_count == 0) {return proxy<F>{};}} while (!ptr->strong_count.compare_exchange_weak(ref_count, ref_count + 1, std::memory_order::relaxed));return proxy<F>{std::in_place_type<strong_compact_ptr<T, Alloc>>, ptr};}};}private:strong_weak_compact_ptr_storage<T, Alloc>* ptr_;
};
看起来像是手写了几个智能指针,暂时没看明白为什么
gpt给的回答里我挑几个看起来靠谱的:
- 自定义控制块,把控制块和指针放在一起
- 标准库的智能指针,operator*的转发不够精细(指qualifier)
- 更轻,减少可能的堆分配
然后可以注意到 weak 和 strong 的实现稍微有点区别,weak 不能直接访问所以保留裸指针;strong 需要直接访问所以直接继承 indirect_ptr
template <class F, class T, class Alloc, class... Args>
constexpr proxy<F> allocate_proxy_impl(const Alloc& alloc, Args&&... args) {if constexpr (proxiable<allocated_ptr<T, Alloc>, F>) {return proxy<F>{std::in_place_type<allocated_ptr<T, Alloc>>, alloc,std::forward<Args>(args)...};} else {return proxy<F>{std::in_place_type<compact_ptr<T, Alloc>>, alloc,std::forward<Args>(args)...};}
}
template <class F, class T, class... Args>
constexpr proxy<F> make_proxy_impl(Args&&... args) {if constexpr (proxiable<inplace_ptr<T>, F>) {return proxy<F>{std::in_place_type<inplace_ptr<T>>, std::in_place,std::forward<Args>(args)...};} else {return allocate_proxy_impl<F, T>(std::allocator<void>{},std::forward<Args>(args)...);}
}
template <class F, class T, class Alloc, class... Args>
constexpr proxy<F> allocate_proxy_shared_impl(const Alloc& alloc,Args&&... args) {if constexpr (weak_ownership_support_traits<F>::applicable) {return proxy<F>{std::in_place_type<strong_compact_ptr<T, Alloc>>, alloc,std::forward<Args>(args)...};} else {return proxy<F>{std::in_place_type<shared_compact_ptr<T, Alloc>>, alloc,std::forward<Args>(args)...};}
}
template <class F, class T, class... Args>
constexpr proxy<F> make_proxy_shared_impl(Args&&... args) {return allocate_proxy_shared_impl<F, T>(std::allocator<void>{},std::forward<Args>(args)...);
}
首先 make_proxy 如果能 in-place 就直接走
否则到 allocate_proxy 如果能 proxy 就用 allocated_ptr 否则用 compact_ptr
然后如果需要共享语义,就必定不能放在对象内部,必定能 proxy,能 weak 就走 strong_compact_ptr,否则就 shared_compact_ptr
template <facade F>
struct observer_facade;
template <facade F>
using proxy_view = proxy<observer_facade<F>>;template <facade F>
struct weak_facade;
template <facade F>
using weak_proxy = proxy<weak_facade<F>>;template <class T, class F>
concept inplace_proxiable_target = proxiable<details::inplace_ptr<T>, F>;template <class T, class F>
concept proxiable_target =proxiable<details::observer_ptr<T&, const T&, T&&, const T&&>,observer_facade<F>>;template <class T>requires(is_bitwise_trivially_relocatable_v<T>)
struct is_bitwise_trivially_relocatable<details::inplace_ptr<T>>: std::true_type {};template <facade F, class T, class... Args>
constexpr proxy<F> make_proxy_inplace(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>)requires(std::is_constructible_v<T, Args...>)
{return proxy<F>{std::in_place_type<details::inplace_ptr<T>>, std::in_place,std::forward<Args>(args)...};
}
template <facade F, class T, class U, class... Args>
constexpr proxy<F>make_proxy_inplace(std::initializer_list<U> il, Args&&... args) noexcept(std::is_nothrow_constructible_v<T, std::initializer_list<U>&, Args...>)requires(std::is_constructible_v<T, std::initializer_list<U>&, Args...>)
{return proxy<F>{std::in_place_type<details::inplace_ptr<T>>, std::in_place,il, std::forward<Args>(args)...};
}
template <facade F, class T>
constexpr proxy<F> make_proxy_inplace(T&& value) noexcept(std::is_nothrow_constructible_v<std::decay_t<T>, T>)requires(std::is_constructible_v<std::decay_t<T>, T>)
{return proxy<F>{std::in_place_type<details::inplace_ptr<std::decay_t<T>>>,std::in_place, std::forward<T>(value)};
}template <facade F, class T>
constexpr proxy_view<F> make_proxy_view(T& value) noexcept {return proxy_view<F>{details::observer_ptr<T&, const T&, T&&, const T&&>{value}};
}
核心就是构造一个 proxy_view,view of proxy,观察者
然后其下有各种各样的从 facade 和 Args 构造 proxy 的构造函数,略去
分发
从这里开始,会有许多丑陋的宏代码出现。
我会给一个展开版本,但是不展开限定符
template <bool Expl, bool Nullable>
struct cast_dispatch_base {template <class P, class D, class T>struct accessor<P, D, T()> {explicit(Expl) operator T() {if constexpr (Nullable) {if (!static_cast<const P&>(*this).has_value()) {return nullptr;}}return proxy_invoke<D, T()>(static_cast<P&>(*this));}};
};
非常简单的分发,注意写在模板参数里的 T() 表示无参数,返回类型为 T 的函数类型
struct upward_conversion_dispatch : cast_dispatch_base<false, true>, internal_dispatch {template <class P, class F>auto operator()(std::in_place_type_t<P>, proxy<F>&& self) const {return converter{[&self]<class F2>(std::in_place_type_t<proxy<F2>>) {if constexpr (is_bitwise_trivially_relocatable_v<P>) {proxy<F2> ret;proxy_helper::trivially_relocate<P>(self, ret);return ret;} else {proxy_helper::resetting_guard<P, F> guard{self};return proxy<F2>{proxy_helper::get_ptr<P, F, qualifier_type::rv>(std::move(self))};}}};}template <class P, class F>decltype(auto) operator()(std::in_place_type_t<P>, const proxy<F>& self) const {return proxy_helper::get_ptr<P, F, qualifier_type::const_lv>(self);}
};
拷贝构造语义
template <class O, class I>
struct add_tuple_reduction : std::type_identity<O> {};
template <class... Os, class I>requires(!std::is_same_v<I, Os> && ...)
struct add_tuple_reduction<std::tuple<Os...>, I>: std::type_identity<std::tuple<Os..., I>> {};
template <class T, class U>
using add_tuple_t = typename add_tuple_reduction<T, U>::type;
template <class O, class... Is>
using merge_tuple_impl_t = recursive_reduction_t<add_tuple_t, O, Is...>;
template <class T, class U>
using merge_tuple_t = instantiated_t<merge_tuple_impl_t, U, T>;
加入 tuple,合并 tuple,requires 用来去重,下同
template <bool IsDirect, class D>
struct merge_conv_traits {template <class... Os>using type = conv_impl<IsDirect, D, Os...>;
};
template <class C1, class C2>
using merge_conv_t = instantiated_t<merge_conv_traits<C1::is_direct, typename C1::dispatch_type>::template type,merge_tuple_t<typename C1::overload_types, typename C2::overload_types>>;template <class Cs1, class C2, class C>
struct add_conv_reduction;
template <class... Cs1, class C2, class... Cs3, class C>
struct add_conv_reduction<std::tuple<Cs1...>, std::tuple<C2, Cs3...>, C>: add_conv_reduction<std::tuple<Cs1..., C2>, std::tuple<Cs3...>, C> {};
template <class... Cs1, class C2, class... Cs3, class C>requires(C::is_direct == C2::is_direct &&std::is_same_v<typename C::dispatch_type, typename C2::dispatch_type>)
struct add_conv_reduction<std::tuple<Cs1...>, std::tuple<C2, Cs3...>, C>: std::type_identity<std::tuple<Cs1..., merge_conv_t<C2, C>, Cs3...>> {};
template <class... Cs, class C>
struct add_conv_reduction<std::tuple<Cs...>, std::tuple<>, C>: std::type_identity<std::tuple<Cs..., merge_conv_t<conv_impl<C::is_direct, typename C::dispatch_type>, C>>> {
};
template <class Cs, class C>
using add_conv_t = typename add_conv_reduction<std::tuple<>, Cs, C>::type;
合并 convention
template <class O>
using observer_upward_conversion_overload =proxy_view<typename overload_traits<O>::return_type::facade_type>()const noexcept;
template <class O, class I>
struct observer_upward_conversion_conv_reduction : std::type_identity<O> {};
template <class... Os, class O>requires(!std::is_same_v<Os, observer_upward_conversion_overload<O>> && ...)
struct observer_upward_conversion_conv_reduction<conv_impl<true, upward_conversion_dispatch, Os...>, O>: std::type_identity<conv_impl<true, upward_conversion_dispatch, Os...,observer_upward_conversion_overload<O>>> {};
template <class... Os>
using observer_upward_conversion_conv = recursive_reduction_t<reduction_traits<observer_upward_conversion_conv_reduction>::template type,conv_impl<true, upward_conversion_dispatch>, Os...>;template <class D, class... Os>
using observer_indirect_conv = conv_impl<false, D, Os...>;
从 facade 升到 proxy_view
template <class C>
struct observer_conv_traits : std::type_identity<void> {};
template <class C>requires(C::is_direct &&std::is_same_v<typename C::dispatch_type, upward_conversion_dispatch>)
struct observer_conv_traits<C>: std::type_identity<instantiated_t<observer_upward_conversion_conv,typename C::overload_types>> {};
template <class C>requires(!C::is_direct)
struct observer_conv_traits<C>: std::type_identity<instantiated_t<observer_indirect_conv, typename C::overload_types,typename C::dispatch_type>> {};
template <class... Cs>
struct observer_facade_conv_impl {using convention_types =composite_t<std::tuple<>, typename observer_conv_traits<Cs>::type...>;
};template <class... Rs>
struct observer_facade_refl_impl {using reflection_types =composite_t<std::tuple<>, std::conditional_t<Rs::is_direct, void, Rs>...>;
};
和上面差不多,如果不是 is_direct 的话用void占位,或者偏特化
template <class P>
auto weak_lock_impl(const P& self) noexceptrequires(requires { static_cast<bool>(self.lock()); })
{return converter{[&self]<class F>(std::in_place_type_t<proxy<F>>) noexcept {auto strong = self.lock();return strong ? proxy<F>{std::move(strong)} : proxy<F>{};}};
}
内层 requires 要求可以 self 可以 lock,但是此时还没有 self,于是外层的 requires 提供了一个模拟环境,神秘语法
这个 lock 的要求约等于 weak_ptr 语义,把 weak_ptr convert 到 proxy<strong_ptr>
template <class O, class I>
struct weak_conv_reduction : std::type_identity<O> {};
template <class... Cs, class I>requires(I::is_direct &&std::is_same_v<typename I::dispatch_type, upward_conversion_dispatch>)
struct weak_conv_reduction<std::tuple<Cs...>, I>: std::type_identity<std::tuple<Cs..., instantiated_t<weak_upward_conversion_conv,typename I::overload_types>>> {};
template <class F, class... Cs>
struct weak_facade_impl {using convention_types = recursive_reduction_t<reduction_traits<weak_conv_reduction>::template type,std::tuple<conv_impl<true, weak_mem_lock, proxy<F>() const noexcept>>,Cs...>;using reflection_types = std::tuple<>;
};
和上面差不多,合并,递归
template <class Cs, class Rs, std::size_t MaxSize, std::size_t MaxAlign,constraint_level Copyability, constraint_level Relocatability,constraint_level Destructibility>
struct basic_facade_builder {template <class D, details::extended_overload... Os>requires(sizeof...(Os) > 0u)using add_indirect_convention = basic_facade_builder<details::add_conv_t<Cs, details::conv_impl<false, D, Os...>>, Rs, MaxSize,MaxAlign, Copyability, Relocatability, Destructibility>;template <class D, details::extended_overload... Os>requires(sizeof...(Os) > 0u)using add_direct_convention = basic_facade_builder<details::add_conv_t<Cs, details::conv_impl<true, D, Os...>>, Rs, MaxSize,MaxAlign, Copyability, Relocatability, Destructibility>;template <class D, details::extended_overload... Os>requires(sizeof...(Os) > 0u)using add_convention = add_indirect_convention<D, Os...>;template <class R>using add_indirect_reflection = basic_facade_builder<Cs, details::add_tuple_t<Rs, details::refl_impl<false, R>>, MaxSize,MaxAlign, Copyability, Relocatability, Destructibility>;template <class R>using add_direct_reflection = basic_facade_builder<Cs, details::add_tuple_t<Rs, details::refl_impl<true, R>>, MaxSize,MaxAlign, Copyability, Relocatability, Destructibility>;template <class R>using add_reflection = add_indirect_reflection<R>;template <facade F, bool WithUpwardConversion = false>using add_facade = basic_facade_builder<details::merge_facade_conv_t<Cs, F, WithUpwardConversion>,details::merge_tuple_t<Rs, typename F::reflection_types>,details::merge_size(MaxSize, F::max_size),details::merge_size(MaxAlign, F::max_align),details::merge_constraint(Copyability, F::copyability),details::merge_constraint(Relocatability, F::relocatability),details::merge_constraint(Destructibility, F::destructibility)>;template <std::size_t PtrSize,std::size_t PtrAlign = details::max_align_of(PtrSize)>requires(std::has_single_bit(PtrAlign) && PtrSize % PtrAlign == 0u)using restrict_layout =basic_facade_builder<Cs, Rs, details::merge_size(MaxSize, PtrSize),details::merge_size(MaxAlign, PtrAlign), Copyability,Relocatability, Destructibility>;template <constraint_level CL>using support_copy =basic_facade_builder<Cs, Rs, MaxSize, MaxAlign,details::merge_constraint(Copyability, CL),Relocatability, Destructibility>;template <constraint_level CL>using support_relocation =basic_facade_builder<Cs, Rs, MaxSize, MaxAlign, Copyability,details::merge_constraint(Relocatability, CL),Destructibility>;template <constraint_level CL>using support_destruction =basic_facade_builder<Cs, Rs, MaxSize, MaxAlign, Copyability,Relocatability,details::merge_constraint(Destructibility, CL)>;template <template <class> class Skill>using add_skill = Skill<basic_facade_builder>;using build = details::facade_impl<Cs, Rs,MaxSize == details::invalid_size ? sizeof(details::ptr_prototype): MaxSize,MaxAlign == details::invalid_size ? alignof(details::ptr_prototype): MaxAlign,Copyability == details::invalid_cl ? constraint_level::none : Copyability,Relocatability == details::invalid_cl ? constraint_level::trivial: Relocatability,Destructibility == details::invalid_cl ? constraint_level::nothrow: Destructibility>;basic_facade_builder() = delete;
};using facade_builder =basic_facade_builder<std::tuple<>, std::tuple<>, details::invalid_size,details::invalid_size, details::invalid_cl,details::invalid_cl, details::invalid_cl>;
封装默认的 facade builder,大部分操作都在这里
struct view_conversion_dispatch : cast_dispatch_base<false, true> {template <class T>PRO4D_STATIC_CALL(auto, T& value) noexceptrequires(requires {{ std::addressof(*value) } noexcept;}){return observer_ptr<decltype(*value), decltype(*std::as_const(value)),decltype(*std::move(value)),decltype(*std::move(std::as_const(value)))>{*value};}
};
template <class F>
using view_conversion_overload = proxy_view<F>() noexcept;struct weak_conversion_dispatch : cast_dispatch_base<false, true> {template <class P>PRO4D_STATIC_CALL(auto, const P& self) noexceptrequires(requires(const typename P::weak_type& w) {{ w.lock() } noexcept -> std::same_as<P>;} && std::is_convertible_v<const P&, typename P::weak_type>){return typename P::weak_type{self};}template <class T, class Alloc>PRO4D_STATIC_CALL(auto, const strong_compact_ptr<T, Alloc>& self) noexcept {return self.get_weak();}
};
template <class F>
using weak_conversion_overload = weak_proxy<F>() const noexcept;
直接从名字就能读出来干什么的
rtti
struct proxy_cast_context {const std::type_info* type_ptr;bool is_ref;bool is_const;void* result_ptr;
};struct proxy_cast_dispatch;
template <class Self, class D, class O>
struct proxy_cast_accessor_impl {using QualifiedSelf = add_qualifier_t<Self, overload_traits<O>::qualifier>;template <class T>friend T proxy_cast(QualifiedSelf self) {static_assert(!std::is_rvalue_reference_v<T>);if constexpr (std::is_lvalue_reference_v<T>) {using U = std::remove_reference_t<T>;void* result = nullptr;proxy_cast_context ctx{.type_ptr = &typeid(T),.is_ref = true,.is_const = std::is_const_v<U>,.result_ptr = &result};proxy_invoke<D, O>(static_cast<QualifiedSelf>(self), ctx);if (result == nullptr) [[unlikely]] {PRO4D_THROW(bad_proxy_cast{});}return *static_cast<U*>(result);} else {std::optional<std::remove_const_t<T>> result;proxy_cast_context ctx{.type_ptr = &typeid(T),.is_ref = false,.is_const = false,.result_ptr = &result};proxy_invoke<D, O>(static_cast<QualifiedSelf>(self), ctx);if (!result.has_value()) [[unlikely]] {PRO4D_THROW(bad_proxy_cast{});}return std::move(*result);}}template <class T>friend T* proxy_cast(std::remove_reference_t<QualifiedSelf>* self) noexceptrequires(std::is_lvalue_reference_v<QualifiedSelf>){void* result = nullptr;proxy_cast_context ctx{.type_ptr = &typeid(T),.is_ref = true,.is_const = std::is_const_v<T>,.result_ptr = &result};proxy_invoke<D, O>(*self, ctx);return static_cast<T*>(result);}
};
手写版 rtti
这个 proxy_invoke 按道理是要更新 ctx.result_ptr,但是我没找到对应的重载
template <class P, class D>
struct accessor<P, D, void(proxy_cast_context)> : proxy_cast_accessor_impl<P, D, void(proxy_cast_context)> {};struct proxy_cast_dispatch {template <class T>void operator()(T&& self, proxy_cast_context ctx) const {if (typeid(T) == *ctx.type_ptr) [[likely]] {if (ctx.is_ref) {if constexpr (std::is_lvalue_reference_v<T>) {if (ctx.is_const || !std::is_const_v<T>) [[likely]] {*static_cast<void**>(ctx.result_ptr) = (void*)std::addressof(self);}}} else {if constexpr (std::is_constructible_v<std::decay_t<T>, T>) {static_cast<std::optional<std::decay_t<T>>*>(ctx.result_ptr)->emplace(std::forward<T>(self));}}}}template <class P, class D, class... ProOs>struct accessor : accessor<P, D, void(proxy_cast_context)>... {};
};
根据是否为引用类型,填写 ctx.result_ptr
struct proxy_typeid_reflector {template <class T>constexpr explicit proxy_typeid_reflector(std::in_place_type_t<T>): info(&typeid(T)) {}constexpr proxy_typeid_reflector(const proxy_typeid_reflector&) = default;template <class Self, class R>struct accessor {friend const std::type_info& proxy_typeid(const Self& self) noexcept {const proxy_typeid_reflector& refl = proxy_reflect<R>(self);return *refl.info;}};const std::type_info* info;
};
根据 typeid 拿到 typeinfo,简单的反射
operator
template <std::size_t N>
struct sign {consteval sign(const char (&str)[N + 1]) {if (str[N] != '\0') {std::abort();}for (std::size_t i = 0; i < N; ++i) {value[i] = str[i];}}char value[N];
};
template <std::size_t N>
sign(const char (&str)[N]) -> sign<N - 1u>;
编译期将字符串字面量保存,基本上是用来 parse 出 operator 的
然后是一大坨 operator dispatch,总之就是实现这些 operator,用 proxy_invoke 转发到对应实现,并构造对应的 accessor
struct implicit_conversion_dispatch: details::cast_dispatch_base<false, false> {template <class T>PRO4D_STATIC_CALL(T&&, T&& self) noexcept {return std::forward<T>(self);}
};
struct explicit_conversion_dispatch : details::cast_dispatch_base<true, false> {template <class T>PRO4D_STATIC_CALL(auto, T&& self) noexcept {return details::converter{[&self]<class U>(std::in_place_type_t<U>) noexcept(std::is_nothrow_constructible_v<U, T>)requires(std::is_constructible_v<U, T>){ return U{std::forward<T>(self)}; }};}
};
using conversion_dispatch = explicit_conversion_dispatch;template <class D>
struct weak_dispatch : D {using D::operator();template <class... Args>[[noreturn]] PRO4D_STATIC_CALL(details::wildcard, Args&&...)requires(!std::is_invocable_v<D, Args...>){PRO4D_THROW(not_implemented{});}
};
隐式转换,显示转换,和对外接口
源代码至此结束,接下来会有一篇应用篇