() cv ref noex;
-};
-```
-
-`(1)` The default implementation of `accessor` is not constructible.
-
-`(2)` When `sizeof...(Os)` is greater than `1`, and `accessor...` are default-constructible, inherits all `accessor
...` types and `using` their `operator return-type-of`. `return-type-of` denotes the *return type* of the overload type `O`.
-
-`(3)` When `sizeof...(Os)` is `1` and the only type `O` in `Os` is `proxy() cv ref noex`, provides an implicit `operator proxy()` with the same *cv ref noex* specifiers. `accessor::operator proxy()` is equivalent to `return invoke() cv ref noex>(static_cast>(*this))` when `static_cast(*this).has_value()` is `true`, or `return nullptr` otherwise.
diff --git a/docs/spec/substitution_dispatch/operator_call.md b/docs/spec/substitution_dispatch/operator_call.md
deleted file mode 100644
index 4da0dff8..00000000
--- a/docs/spec/substitution_dispatch/operator_call.md
+++ /dev/null
@@ -1,8 +0,0 @@
-# `substitution_dispatch::operator()`
-
-```cpp
-template
-T&& operator()(T&& value) const noexcept; // exposition-only
-```
-
-Returns `std::forward(value)`. When `T` is not cv- or ref-qualified and [`is_bitwise_trivially_relocatable_v`](../is_bitwise_trivially_relocatable.md) is `true`, conversion from the return value to any `proxy` type shall perform bitwise trivial relocation and does not require that `T` is move-constructible.
diff --git a/docs/spec/weak_proxy.md b/docs/spec/weak_proxy.md
index 0c71ce39..578df57e 100644
--- a/docs/spec/weak_proxy.md
+++ b/docs/spec/weak_proxy.md
@@ -26,7 +26,7 @@ using weak_proxy = proxy>;
| Name | Description |
| ---------------------------------- | ----------- |
| `super_types`
*(since 5.0.0)* | A [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type transformed from `typename F::super_types`. Specifically, for each super `S` in `typename F::super_types`, `weak_facade` is included. |
-| `convention_types` | A [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type that always contains a direct convention whose dispatch type denotes the member function `lock` and whose overload has signature `proxy() const noexcept`. Calling this overload attempts to obtain a strong `proxy`; it returns an empty `proxy` if the object has expired. For each direct convention `C` in `typename F::convention_types` whose `dispatch_type` is [`substitution_dispatch`](./substitution_dispatch/README.md), a transformed convention `C'` is also included, whose `is_direct` is `true`, `dispatch_type` is still `substitution_dispatch`, and whose `overload_type` is `typename C::overload_type` with a return type of `proxy` replaced by `weak_proxy`, preserving qualifiers. All other conventions from `F` are discarded. |
+| `convention_types` | A [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type that contains a single direct convention whose dispatch type denotes the member function `lock` and whose overload has signature `proxy() const noexcept`. Calling this overload attempts to obtain a strong `proxy`; it returns an empty `proxy` if the object has expired. All conventions from `F` are discarded. |
| `reflection_types` | A [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type that contains no types. |
## Member Constants of `weak_facade`
diff --git a/include/proxy/v4/detail/core.h b/include/proxy/v4/detail/core.h
index 2d725dfe..7ecca2ef 100644
--- a/include/proxy/v4/detail/core.h
+++ b/include/proxy/v4/detail/core.h
@@ -58,7 +58,6 @@ template
class proxy_indirect_accessor;
template
class PRO4D_ENFORCE_EBO proxy;
-struct substitution_dispatch;
template
struct is_bitwise_trivially_relocatable
@@ -257,14 +256,6 @@ struct proxy_helper {
static const M& get_meta(const proxy_indirect_accessor& p) noexcept {
return get_meta(as_proxy(p));
}
- template
- static proxy make_relocated(void* src) noexcept {
- proxy ret;
- std::uninitialized_copy_n(static_cast(src), sizeof(P),
- ret.ptr_);
- ret.meta_ = decltype(ret.meta_){std::in_place_type};
- return ret;
- }
template
static void* get_ptr(proxy& p) noexcept {
return p.ptr_;
@@ -440,27 +431,6 @@ struct erased_context {
void* p_;
};
-// TODO: remove together with substitution_dispatch.
-#define PRO4D_DEF_SUBSTITUTION_CONTEXT(...) \
- template \
- struct erased_context() && __VA_ARGS__> { \
- template \
- friend proxy invoke(erased_context ctx) __VA_ARGS__ { \
- if constexpr (is_bitwise_trivially_relocatable_v) { \
- return proxy_helper::make_relocated
(ctx.p_); \
- } else { \
- auto* self = std::launder(static_cast
(ctx.p_)); \
- destroying_guard
guard{self}; \
- return proxy{std::move(*self)}; \
- } \
- } \
- \
- void* p_; \
- }
-PRO4D_DEF_SUBSTITUTION_CONTEXT();
-PRO4D_DEF_SUBSTITUTION_CONTEXT(noexcept);
-#undef PRO4D_DEF_SUBSTITUTION_CONTEXT
template
using erased_invoker_t = invoker, O>;
@@ -1627,25 +1597,14 @@ class observer_ptr {
LR lr_;
};
-template
-using observer_substitution_overload =
- proxy_view::facade_type>() const noexcept;
template
struct observer_conv_traits : std::type_identity {};
-template
- requires(C::is_direct &&
- std::is_same_v)
-struct observer_conv_traits
- : std::type_identity>> {};
template
requires(!C::is_direct)
struct observer_conv_traits : std::type_identity {};
template
-using observer_conv_types = merge_tuples_t<
- std::tuple<>,
- composite_t, typename observer_conv_traits::type...>>;
+using observer_conv_types =
+ composite_t, typename observer_conv_traits::type...>;
template
using observer_refl_types =
composite_t, std::conditional_t...>;
@@ -1675,52 +1634,8 @@ using weak_lock_overload = proxy() const noexcept;
template
using weak_super_types = std::tuple...>;
-template
-struct weak_substitution_overload_traits;
-#define PRO4D_DEF_WEAK_SUBSTITUTION_OVERLOAD_TRAITS(oq, pq, ne, ...) \
- template \
- struct weak_substitution_overload_traits() oq ne> \
- : std::type_identity() oq ne> {};
-PRO4D_DEF_OVERLOAD_SPECIALIZATIONS(PRO4D_DEF_WEAK_SUBSTITUTION_OVERLOAD_TRAITS)
-#undef PRO4D_DEF_WEAK_SUBSTITUTION_OVERLOAD_TRAITS
-template
-struct weak_conv_traits : std::type_identity {};
-template
- requires(C::is_direct &&
- std::is_same_v)
-struct weak_conv_traits
- : std::type_identity::type>> {};
-template
-using weak_conv_types = merge_tuples_t<
- std::tuple>>,
- composite_t, typename weak_conv_traits::type...>>;
-
} // namespace detail
-struct PRO4D_ENFORCE_EBO substitution_dispatch
- : detail::cast_dispatch_base {
- template
- PRO4D_STATIC_CALL(T&&, T&& self) noexcept {
- return std::forward(self);
- }
-
- // This overload is not reachable at runtime, but is necessary to ensure
- // substitution_dispatch is SFINAE-friendly.
- template
- PRO4D_STATIC_CALL(auto, T&&) noexcept
- requires(std::is_same_v> &&
- is_bitwise_trivially_relocatable_v)
- {
- return detail::converter{
- [](std::in_place_type_t>) noexcept -> proxy
- requires(proxiable)
- { PRO4D_UNREACHABLE(); }};
- }
-};
-
template
struct observer_facade
: detail::facade_impl<
@@ -1738,8 +1653,9 @@ struct weak_facade
: detail::facade_impl<
detail::specialization_t,
- detail::specialization_t,
+ std::tuple>>,
std::tuple<>, F::max_size, F::max_align, F::copyability,
F::relocatability, F::destructibility> {
using strong_type = F;
diff --git a/include/proxy/v4/detail/facade_creation.h b/include/proxy/v4/detail/facade_creation.h
index e9c5cd78..69ce9259 100644
--- a/include/proxy/v4/detail/facade_creation.h
+++ b/include/proxy/v4/detail/facade_creation.h
@@ -31,36 +31,6 @@ consteval std::size_t max_align_of(std::size_t value) {
using ptr_prototype = void* [2];
-template
-using copy_conversion_overload =
- proxy() const& noexcept(CL >= constraint_level::nothrow);
-template
-using move_conversion_overload =
- proxy() && noexcept(CL >= constraint_level::nothrow);
-template
-struct add_substitution_conv
- : std::type_identity,
- std::conditional_t<
- CCL == constraint_level::none, void,
- conv_impl>>,
- std::conditional_t<
- RCL == constraint_level::none, void,
- conv_impl>>>>> {
-};
-template
-struct add_substitution_conv : std::type_identity {
-};
-template
-using add_substitution_conv_t =
- add_substitution_conv::type;
-
} // namespace detail
template ;
template
- using add_facade_with_substitution = basic_facade_builder<
- detail::composite_t, detail::add_substitution_conv_t, Rs,
- detail::merge_size(MaxSize, F::max_size),
- detail::merge_size(MaxAlign, F::max_align),
- detail::merge_constraint(Copyability, F::copyability),
- detail::merge_constraint(Relocatability, F::relocatability),
- detail::merge_constraint(Destructibility, F::destructibility)>;
+ using add_facade_with_substitution = add_facade;
template
requires(detail::is_layout_well_formed(PtrSize, PtrAlign))
diff --git a/include/proxy/v4/detail/skills.h b/include/proxy/v4/detail/skills.h
index 0c64e581..a8bbd4f3 100644
--- a/include/proxy/v4/detail/skills.h
+++ b/include/proxy/v4/detail/skills.h
@@ -42,7 +42,32 @@ struct enabled_t {};
template class TT, class... Ctx>
concept enabled_for = std::is_base_of_v, T>;
-struct view_conversion_dispatch : cast_dispatch_base {
+#define PRO4D_DEF_FAW_CAST_ACCESSOR(oq, pq, ne, ...) \
+ template class TargetFacade> \
+ struct accessor, D, proxy>() oq ne> { \
+ template \
+ requires(std::is_convertible_v>, \
+ proxy>>) \
+ operator proxy>() oq ne { \
+ if (!static_cast&>(*this).has_value()) { \
+ return nullptr; \
+ } \
+ return invoke< \
+ D, proxy pq, proxy>>, \
+ F2, F>>>() oq ne>(static_cast pq>(*this)); \
+ } \
+ }
+struct faw_cast_dispatch_base {
+ template
+ struct accessor {
+ accessor() = delete;
+ };
+ PRO4D_DEF_OVERLOAD_SPECIALIZATIONS(PRO4D_DEF_FAW_CAST_ACCESSOR)
+};
+#undef PRO4D_DEF_FAW_CAST_ACCESSOR
+
+struct view_conversion_dispatch : faw_cast_dispatch_base {
template
PRO4D_STATIC_CALL(auto, T& value) noexcept
requires(requires {
@@ -57,7 +82,7 @@ struct view_conversion_dispatch : cast_dispatch_base {
template
using view_conversion_overload = proxy_view() & noexcept;
-struct weak_conversion_dispatch : cast_dispatch_base {
+struct weak_conversion_dispatch : faw_cast_dispatch_base {
template
PRO4D_STATIC_CALL(auto, const P& self) noexcept
requires(requires(const typename P::weak_type& w) {
diff --git a/include/proxy/v4/proxy.ixx b/include/proxy/v4/proxy.ixx
index cdf4cce8..19303be9 100644
--- a/include/proxy/v4/proxy.ixx
+++ b/include/proxy/v4/proxy.ixx
@@ -40,7 +40,6 @@ using v4::proxy_indirect_accessor;
using v4::proxy_invoke;
using v4::proxy_reflect;
using v4::proxy_view;
-using v4::substitution_dispatch;
using v4::weak_dispatch;
using v4::weak_facade;
using v4::weak_proxy;
diff --git a/tests/proxy_creation_tests.cpp b/tests/proxy_creation_tests.cpp
index 3308f179..579fda88 100644
--- a/tests/proxy_creation_tests.cpp
+++ b/tests/proxy_creation_tests.cpp
@@ -168,11 +168,10 @@ struct TestSharedStringable
::add_direct_reflection //
::build {};
-struct TestWeakSharedStringable
- : pro::facade_builder //
- ::add_facade_with_substitution //
- ::add_skill //
- ::build {};
+struct TestWeakSharedStringable : pro::facade_builder //
+ ::add_facade //
+ ::add_skill //
+ ::build {};
static_assert(pro::proxiable);
static_assert(!pro::proxiable);
@@ -932,6 +931,55 @@ TEST(ProxyCreationTests,
ASSERT_TRUE(tracker.GetOperations() == expected_ops);
}
+TEST(ProxyCreationTests, TestMakeProxyShared_WeakOfSuper) {
+ struct WeakSuper
+ : pro::facade_builder //
+ ::support_copy //
+ ::add_convention //
+ ::add_skill //
+ ::build {};
+ struct WeakDerived
+ : pro::facade_builder //
+ ::add_facade //
+ ::add_convention, int(int) const> //
+ ::build {};
+ auto p1 = pro::make_proxy_shared(123);
+ pro::weak_proxy p2 = p1;
+ {
+ auto p3 = p2.lock();
+ ASSERT_TRUE(p3.has_value());
+ ASSERT_EQ(ToString(*p3), "123");
+ }
+ p1.reset();
+ ASSERT_FALSE(p2.lock().has_value());
+ pro::proxy p4;
+ pro::weak_proxy p5 = p4;
+ ASSERT_FALSE(p5.has_value());
+}
+
+TEST(ProxyCreationTests, TestMakeProxyShared_WeakOfSuperWithoutSkill) {
+ struct WeakSuper
+ : pro::facade_builder //
+ ::support_copy //
+ ::add_convention //
+ ::build {};
+ struct WeakDerived
+ : pro::facade_builder //
+ ::add_facade //
+ ::add_skill //
+ ::add_convention, int(int) const> //
+ ::build {};
+ auto p1 = pro::make_proxy_shared(123);
+ pro::weak_proxy p2 = p1;
+ {
+ auto p3 = p2.lock();
+ ASSERT_TRUE(p3.has_value());
+ ASSERT_EQ(ToString(*p3), "123");
+ }
+ p1.reset();
+ ASSERT_FALSE(p2.lock().has_value());
+}
+
TEST(ProxyCreationTests, TestMakeProxyShared_SharedCompact_FromValue) {
utils::LifetimeTracker tracker;
std::vector expected_ops;
diff --git a/tests/proxy_dispatch_tests.cpp b/tests/proxy_dispatch_tests.cpp
index 679940e3..96c5bb85 100644
--- a/tests/proxy_dispatch_tests.cpp
+++ b/tests/proxy_dispatch_tests.cpp
@@ -831,28 +831,6 @@ TEST(ProxyDispatchTests, TestFreeAsMemDispatch) {
ASSERT_EQ(p->ToString(), "123");
}
-TEST(ProxyDispatchTests, TestSubstitutionDispatch) {
-#ifdef PRO4D_HAS_FORMAT
- struct Base : pro::facade_builder //
- ::add_skill //
- ::build {};
- struct TestFacade : pro::facade_builder //
- ::add_direct_convention() const&,
- pro::proxy() &&> //
- ::build {};
- pro::proxy p1 = pro::make_proxy(123);
- pro::proxy p2 = p1;
- ASSERT_TRUE(p1.has_value());
- ASSERT_EQ(std::format("{}", *p2), "123");
- pro::proxy p3 = std::move(p1);
- ASSERT_FALSE(p1.has_value());
- ASSERT_EQ(std::format("{}", *p3), "123");
-#else
- GTEST_SKIP() << "std::format not available";
-#endif // PRO4D_HAS_FORMAT
-}
-
TEST(ProxyDispatchTests, TestSuperConversion) {
#ifdef PRO4D_HAS_FORMAT
struct Base : pro::facade_builder //
diff --git a/tests/proxy_lifetime_tests.cpp b/tests/proxy_lifetime_tests.cpp
index 0e5ea6d3..37ed5f34 100644
--- a/tests/proxy_lifetime_tests.cpp
+++ b/tests/proxy_lifetime_tests.cpp
@@ -36,7 +36,7 @@ struct TestThrowingDestructionFacade
struct TestRttiFacade : pro::facade_builder //
::add_direct_reflection //
- ::add_facade_with_substitution //
+ ::add_facade //
::build {};
// Additional static asserts for super conversion
@@ -1304,8 +1304,9 @@ TEST(ProxyLifetimeTests, Test_CopySubstitution_MixedMetaStorage) {
::support_relocation //
::support_destruction //
::build {};
- struct Derived : pro::facade_builder //
- ::add_facade_with_substitution //
+ struct Derived : pro::facade_builder //
+ ::add_direct_reflection //
+ ::add_facade //
::build {};
static_assert(
pro::detail::specialization_of //
- ::add_skill //
+ struct TestFacade2 : pro::facade_builder //
+ ::add_facade //
+ ::add_skill //
::build {};
pro::proxy p1;
pro::proxy_view p2 = p1;
@@ -162,7 +162,7 @@ TEST(ProxyViewTests, TestSubstitution_FromValue) {
::build {};
struct TestFacade2 : pro::facade_builder //
::support_copy //
- ::add_facade_with_substitution //
+ ::add_facade //
::add_skill //
::build {};
pro::proxy p1 = pro::make_proxy(123);
@@ -215,6 +215,44 @@ TEST(ProxyViewTests, TestFacadeAware_FromSuper) {
ASSERT_EQ((*p2) + 1, 124);
}
+TEST(ProxyViewTests, TestFacadeAware_ToSuperView) {
+ struct TestFacade1
+ : pro::facade_builder //
+ ::add_convention //
+ ::add_skill //
+ ::build {};
+ struct TestFacade2
+ : pro::facade_builder //
+ ::add_facade //
+ ::add_convention, int(int) const> //
+ ::build {};
+ pro::proxy p1 = pro::make_proxy(123);
+ pro::proxy_view