Skip to content
This repository was archived by the owner on Jan 29, 2026. It is now read-only.

Commit b172bae

Browse files
authored
Improve accessibility in debugging (#200)
1 parent b8eb64f commit b172bae

2 files changed

Lines changed: 63 additions & 24 deletions

File tree

docs/ProAccessible.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Given that `F` is a type meeting the [*ProBasicFacade* requirements](ProBasicFac
44

55
| Expressions | Semantics |
66
| ------------------------------------------- | ------------------------------------------------------------ |
7-
| `typename T::template accessor<F, Args...>` | A type that provides accessibility to `proxy`. It shall be a trivial class type and not [final](https://en.cppreference.com/w/cpp/language/final). |
7+
| `typename T::template accessor<F, Args...>` | A type that provides accessibility to `proxy`. It shall be a *nothrow-default-constructible*, *trivially-copyable* type, and shall not be [final](https://en.cppreference.com/w/cpp/language/final). |
88

99
## See Also
1010

proxy.h

Lines changed: 62 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -450,30 +450,37 @@ struct lifetime_meta_traits<MP, constraint_level::nontrivial>
450450
template <template <bool> class MP, constraint_level C>
451451
using lifetime_meta_t = typename lifetime_meta_traits<MP, C>::type;
452452

453+
template <class F> struct proxy_indirect_accessor;
453454
template <class... As>
454455
class ___PRO_ENFORCE_EBO composite_accessor_impl : public As... {
455456
template <class> friend class pro::proxy;
457+
template <class F> friend struct proxy_indirect_accessor;
456458

457459
composite_accessor_impl() noexcept = default;
458460
composite_accessor_impl(const composite_accessor_impl&) noexcept = default;
459461
composite_accessor_impl& operator=(const composite_accessor_impl&) noexcept
460462
= default;
461463
};
462464

465+
template <class T>
466+
struct accessor_traits_impl : std::type_identity<void> {};
467+
template <class T>
468+
requires(std::is_nothrow_default_constructible_v<T> &&
469+
std::is_trivially_copyable_v<T> && !std::is_final_v<T>)
470+
struct accessor_traits_impl<T> : std::type_identity<T> {};
463471
template <class SFINAE, class T, class... Args>
464472
struct sfinae_accessor_traits : std::type_identity<void> {};
465473
template <class T, class... Args>
466474
struct sfinae_accessor_traits<
467475
std::void_t<typename T::template accessor<Args...>>, T, Args...>
468-
: std::type_identity<typename T::template accessor<Args...>> {};
476+
: accessor_traits_impl<typename T::template accessor<Args...>> {};
469477
template <class T, class... Args>
470478
using accessor_t = typename sfinae_accessor_traits<void, T, Args...>::type;
471479

472480
template <bool IS_DIRECT, class F, class O, class I>
473481
struct composite_accessor_reduction : std::type_identity<O> {};
474482
template <bool IS_DIRECT, class F, class... As, class I>
475-
requires(IS_DIRECT == I::is_direct && std::is_trivial_v<accessor_t<I, F>> &&
476-
!std::is_final_v<accessor_t<I, F>>)
483+
requires(IS_DIRECT == I::is_direct && !std::is_void_v<accessor_t<I, F>>)
477484
struct composite_accessor_reduction<
478485
IS_DIRECT, F, composite_accessor_impl<As...>, I>
479486
{ using type = composite_accessor_impl<As..., accessor_t<I, F>>; };
@@ -508,7 +515,6 @@ consteval bool is_facade_constraints_well_formed() {
508515
}
509516
return false;
510517
}
511-
struct empty_proxy_base {};
512518
template <class F, class... Cs>
513519
struct facade_conv_traits_impl : inapplicable_traits {};
514520
template <class F, class... Cs> requires(conv_traits<Cs>::applicable && ...)
@@ -563,12 +569,14 @@ struct facade_traits<F>
563569
using direct_accessor = merged_composite_accessor<
564570
typename facade_traits::conv_direct_accessor,
565571
typename facade_traits::refl_direct_accessor>;
566-
using base = std::conditional_t<std::is_same_v<direct_accessor,
567-
composite_accessor_impl<>>, empty_proxy_base, direct_accessor>;
568572
static constexpr bool has_indirection = !std::is_same_v<
569573
typename facade_traits::indirect_accessor, composite_accessor_impl<>>;
570574
};
571575

576+
template <class F> struct proxy_indirect_accessor {};
577+
template <class F> requires(facade_traits<F>::has_indirection)
578+
struct proxy_indirect_accessor<F> : facade_traits<F>::indirect_accessor {};
579+
572580
using ptr_prototype = void*[2];
573581

574582
template <class M>
@@ -672,14 +680,32 @@ concept proxiable = facade<F> && sizeof(P) <= F::constraints.max_size &&
672680
details::facade_traits<F>::template refl_applicable_ptr<P>;
673681

674682
template <class F>
675-
class proxy : public details::facade_traits<F>::base {
683+
class proxy : public details::facade_traits<F>::direct_accessor {
676684
static_assert(facade<F>);
677685
friend struct details::proxy_helper<F>;
678686
using _Traits = details::facade_traits<F>;
687+
using _IA = details::proxy_indirect_accessor<F>;
679688

680689
public:
690+
#ifdef NDEBUG
681691
proxy() noexcept = default;
682-
proxy(std::nullptr_t) noexcept {}
692+
#else
693+
proxy() noexcept {
694+
if constexpr (_Traits::has_indirection) {
695+
std::ignore = static_cast<_IA* (proxy::*)() noexcept>(&proxy::operator->);
696+
std::ignore = static_cast<const _IA* (proxy::*)() const noexcept>(
697+
&proxy::operator->);
698+
std::ignore = static_cast<_IA& (proxy::*)() & noexcept>(&proxy::operator*);
699+
std::ignore = static_cast<const _IA& (proxy::*)() const& noexcept>(
700+
&proxy::operator*);
701+
std::ignore = static_cast<_IA&& (proxy::*)() && noexcept>(
702+
&proxy::operator*);
703+
std::ignore = static_cast<const _IA&& (proxy::*)() const&& noexcept>(
704+
&proxy::operator*);
705+
}
706+
}
707+
#endif // NDEBUG
708+
proxy(std::nullptr_t) noexcept : proxy() {}
683709
proxy(const proxy&) noexcept requires(F::constraints.copyability ==
684710
constraint_level::trivial) = default;
685711
proxy(const proxy& rhs)
@@ -709,20 +735,20 @@ class proxy : public details::facade_traits<F>::base {
709735
template <class P>
710736
proxy(P&& ptr) noexcept(std::is_nothrow_constructible_v<std::decay_t<P>, P>)
711737
requires(proxiable<std::decay_t<P>, F> &&
712-
std::is_constructible_v<std::decay_t<P>, P>)
738+
std::is_constructible_v<std::decay_t<P>, P>) : proxy()
713739
{ initialize<std::decay_t<P>>(std::forward<P>(ptr)); }
714740
template <proxiable<F> P, class... Args>
715741
explicit proxy(std::in_place_type_t<P>, Args&&... args)
716742
noexcept(std::is_nothrow_constructible_v<P, Args...>)
717-
requires(std::is_constructible_v<P, Args...>)
743+
requires(std::is_constructible_v<P, Args...>) : proxy()
718744
{ initialize<P>(std::forward<Args>(args)...); }
719745
template <proxiable<F> P, class U, class... Args>
720746
explicit proxy(std::in_place_type_t<P>, std::initializer_list<U> il,
721747
Args&&... args)
722748
noexcept(std::is_nothrow_constructible_v<
723749
P, std::initializer_list<U>&, Args...>)
724750
requires(std::is_constructible_v<P, std::initializer_list<U>&, Args...>)
725-
{ initialize<P>(il, std::forward<Args>(args)...); }
751+
: proxy() { initialize<P>(il, std::forward<Args>(args)...); }
726752
proxy& operator=(std::nullptr_t)
727753
noexcept(F::constraints.destructibility >= constraint_level::nothrow)
728754
requires(F::constraints.destructibility >= constraint_level::nontrivial)
@@ -826,18 +852,18 @@ class proxy : public details::facade_traits<F>::base {
826852
requires(std::is_constructible_v<P, std::initializer_list<U>&, Args...> &&
827853
F::constraints.destructibility >= constraint_level::nontrivial)
828854
{ reset(); return initialize<P>(il, std::forward<Args>(args)...); }
829-
auto operator->() noexcept requires(_Traits::has_indirection)
855+
_IA* operator->() noexcept requires(_Traits::has_indirection)
830856
{ return std::addressof(ia_); }
831-
auto operator->() const noexcept requires(_Traits::has_indirection)
857+
const _IA* operator->() const noexcept requires(_Traits::has_indirection)
832858
{ return std::addressof(ia_); }
833-
auto& operator*() & noexcept requires(_Traits::has_indirection)
859+
_IA& operator*() & noexcept requires(_Traits::has_indirection)
834860
{ return ia_; }
835-
auto& operator*() const& noexcept requires(_Traits::has_indirection)
861+
const _IA& operator*() const& noexcept requires(_Traits::has_indirection)
836862
{ return ia_; }
837-
auto&& operator*() && noexcept requires(_Traits::has_indirection)
838-
{ return std::forward<typename _Traits::indirect_accessor>(ia_); }
839-
auto&& operator*() const&& noexcept requires(_Traits::has_indirection)
840-
{ return std::forward<const typename _Traits::indirect_accessor>(ia_); }
863+
_IA&& operator*() && noexcept requires(_Traits::has_indirection)
864+
{ return std::forward<_IA>(ia_); }
865+
const _IA&& operator*() const&& noexcept requires(_Traits::has_indirection)
866+
{ return std::forward<const _IA>(ia_); }
841867

842868
friend void swap(proxy& lhs, proxy& rhs) noexcept(noexcept(lhs.swap(rhs)))
843869
{ lhs.swap(rhs); }
@@ -856,7 +882,7 @@ class proxy : public details::facade_traits<F>::base {
856882
}
857883

858884
[[___PRO_NO_UNIQUE_ADDRESS_ATTRIBUTE]]
859-
typename _Traits::indirect_accessor ia_;
885+
_IA ia_;
860886
details::meta_ptr<typename _Traits::meta> meta_;
861887
alignas(F::constraints.max_align) std::byte ptr_[F::constraints.max_size];
862888
};
@@ -1107,9 +1133,9 @@ proxy<F> make_proxy(T&& value) {
11071133
struct ___PRO_ENFORCE_EBO accessor { accessor() = delete; }; \
11081134
template <class __F, class __C, class... __Os> \
11091135
requires(sizeof...(__Os) > 1u && \
1110-
(::std::is_trivial_v<accessor<__F, __C, __Os>> && ...)) \
1136+
(::std::is_constructible_v<accessor<__F, __C, __Os>> && ...)) \
11111137
struct accessor<__F, __C, __Os...> : accessor<__F, __C, __Os>... \
1112-
{ using accessor<__F, __C, __Os>:: __VA_ARGS__ ...; }; \
1138+
{ using accessor<__F, __C, __Os>::__VA_ARGS__...; }; \
11131139
__MACRO(, *this, __VA_ARGS__); \
11141140
__MACRO(noexcept, *this, __VA_ARGS__); \
11151141
__MACRO(&, *this, __VA_ARGS__); \
@@ -1129,7 +1155,7 @@ proxy<F> make_proxy(T&& value) {
11291155
struct ___PRO_ENFORCE_EBO accessor { accessor() = delete; }; \
11301156
template <class __F, class __C, class... __Os> \
11311157
requires(sizeof...(__Os) > 1u && \
1132-
(::std::is_trivial_v<accessor<__F, __C, __Os>> && ...)) \
1158+
(::std::is_constructible_v<accessor<__F, __C, __Os>> && ...)) \
11331159
struct accessor<__F, __C, __Os...> : accessor<__F, __C, __Os>... {}; \
11341160
__MACRO(,, accessor& __self, __self, __VA_ARGS__); \
11351161
__MACRO(noexcept, noexcept, accessor& __self, __self, __VA_ARGS__); \
@@ -1150,6 +1176,13 @@ proxy<F> make_proxy(T&& value) {
11501176
__MACRO(const&& noexcept, noexcept, const accessor&& __self, \
11511177
::std::forward<const accessor>(__self), __VA_ARGS__);
11521178

1179+
#ifdef NDEBUG
1180+
#define ___PRO_GEN_SYMBOL_FOR_MEM_ACCESSOR(...)
1181+
#else
1182+
#define ___PRO_GEN_SYMBOL_FOR_MEM_ACCESSOR(...) \
1183+
accessor() noexcept { ::std::ignore = &accessor::__VA_ARGS__; }
1184+
#endif // NDEBUG
1185+
11531186
namespace details {
11541187

11551188
constexpr std::size_t invalid_size = std::numeric_limits<std::size_t>::max();
@@ -1227,6 +1260,7 @@ struct facade_impl {
12271260
#define ___PRO_DEF_UPWARD_CONVERSION_ACCESSOR(Q, SELF, ...) \
12281261
template <class F2, class C> \
12291262
struct accessor<F2, C, proxy<F>() Q> { \
1263+
___PRO_GEN_SYMBOL_FOR_MEM_ACCESSOR(__VA_ARGS__) \
12301264
__VA_ARGS__ () Q { \
12311265
if (access_proxy<F2>(SELF).has_value()) { \
12321266
return proxy_invoke<C, proxy<F>() Q>(access_proxy<F2>(SELF)); \
@@ -1389,12 +1423,14 @@ struct operator_dispatch;
13891423
#define ___PRO_DEF_LHS_LEFT_OP_ACCESSOR(Q, SELF, ...) \
13901424
template <class F, class C, class R> \
13911425
struct accessor<F, C, R() Q> { \
1426+
___PRO_GEN_SYMBOL_FOR_MEM_ACCESSOR(__VA_ARGS__) \
13921427
R __VA_ARGS__ () Q \
13931428
{ return proxy_invoke<C, R() Q>(access_proxy<F>(SELF)); } \
13941429
}
13951430
#define ___PRO_DEF_LHS_ANY_OP_ACCESSOR(Q, SELF, ...) \
13961431
template <class F, class C, class R, class... Args> \
13971432
struct accessor<F, C, R(Args...) Q> { \
1433+
___PRO_GEN_SYMBOL_FOR_MEM_ACCESSOR(__VA_ARGS__) \
13981434
R __VA_ARGS__ (Args... args) Q { \
13991435
return proxy_invoke<C, R(Args...) Q>( \
14001436
access_proxy<F>(SELF), std::forward<Args>(args)...); \
@@ -1460,6 +1496,7 @@ struct operator_dispatch;
14601496
#define ___PRO_DEF_LHS_ASSIGNMENT_OP_ACCESSOR(Q, SELF, ...) \
14611497
template <class F, class C, class R, class Arg> \
14621498
struct accessor<F, C, R(Arg) Q> { \
1499+
___PRO_GEN_SYMBOL_FOR_MEM_ACCESSOR(__VA_ARGS__) \
14631500
decltype(auto) __VA_ARGS__ (Arg arg) Q { \
14641501
proxy_invoke<C, R(Arg) Q>( \
14651502
access_proxy<F>(SELF), std::forward<Arg>(arg)); \
@@ -1577,6 +1614,7 @@ struct operator_dispatch<"[]", false> {
15771614
#define ___PRO_DEF_CONVERSION_ACCESSOR(Q, SELF, ...) \
15781615
template <class F, class C> \
15791616
struct accessor<F, C, T() Q> { \
1617+
___PRO_GEN_SYMBOL_FOR_MEM_ACCESSOR(__VA_ARGS__) \
15801618
explicit(Expl) __VA_ARGS__ () Q \
15811619
{ return proxy_invoke<C, T() Q>(access_proxy<F>(SELF)); } \
15821620
}
@@ -1604,6 +1642,7 @@ struct conversion_dispatch {
16041642
#define ___PRO_DEF_MEM_ACCESSOR(__Q, __SELF, ...) \
16051643
template <class __F, class __C, class __R, class... __Args> \
16061644
struct accessor<__F, __C, __R(__Args...) __Q> { \
1645+
___PRO_GEN_SYMBOL_FOR_MEM_ACCESSOR(__VA_ARGS__) \
16071646
__R __VA_ARGS__ (__Args... __args) __Q { \
16081647
return ::pro::proxy_invoke<__C, __R(__Args...) __Q>( \
16091648
::pro::access_proxy<__F>(__SELF), \

0 commit comments

Comments
 (0)