diff --git a/docs/spec/ProFacade.md b/docs/spec/ProFacade.md
index 1ca2515..60221a4 100644
--- a/docs/spec/ProFacade.md
+++ b/docs/spec/ProFacade.md
@@ -12,11 +12,10 @@ A type `F` meets the *ProFacade* requirements of a type `P` if `F` meets the [*P
| `F::relocatability` | A [core constant expression](https://en.cppreference.com/w/cpp/language/constant_expression) of type [`constraint_level`](constraint_level.md) that defines the required relocatability of `P`. |
| `F::destructibility` | A [core constant expression](https://en.cppreference.com/w/cpp/language/constant_expression) of type [`constraint_level`](constraint_level.md) that defines the required destructibility of `P`. |
-*Since 4.0.2*: `P` shall be a pointer-like type eligible for `proxy`. A type `P` is eligible if `P` is not a specialization of `proxy` and the following condition is satisfied:
+*Since 4.0.2*: `P` shall be a pointer-like type eligible for `proxy`. A type `P` is eligible if the following condition is satisfied:
```cpp
-(requires { *std::declval
(); } || requires { typename P::element_type; }) &&
-requires { typename std::pointer_traits
::element_type; }
+(std::is_pointer_v || requires { typename T::element_type; } || requires(T val) { *val; }) && requires { typename std::pointer_traits::element_type; }
```
In other words, `P` either supports dereferencing or provides an `element_type`, and `std::pointer_traits` yields a valid `element_type`.
diff --git a/docs/spec/proxy/assignment.md b/docs/spec/proxy/assignment.md
index d3558bc..8934ce1 100644
--- a/docs/spec/proxy/assignment.md
+++ b/docs/spec/proxy/assignment.md
@@ -38,7 +38,7 @@ Assigns a new value to `proxy` or destroys the contained value.
- `(1)` Destroys the current contained value if it exists. After the call, `*this` does not contain a value.
- `(2)` Copy assignment operator copies the contained value of `rhs` to `*this`. If `rhs` does not contain a value, it destroys the contained value of `*this` (if any) as if by `auto(rhs).swap(*this)`. The copy assignment is trivial when `F::copyability == constraint_level::trivial` is `true`.
- `(3)` Move assignment operator moves the contained value of `rhs` to `*this`. If `rhs` does not contain a value, it destroys the contained value of `*this` (if any). If the move construction throws when `F::relocatability == constraint_level::nontrivial`, `*this` does not contain a value. After move assignment, `rhs` is in a valid state with an unspecified value. The move assignment operator does not participate in overload resolution when `F::copyability == constraint_level::trivial`, falling back to the trivial copy assignment operator.
-- `(4)` Let `VP` be `std::decay_t
`. Sets the contained value to an object of type `VP`, direct-non-list-initialized with `std::forward
(ptr)`. Participates in overload resolution only if `VP` is a pointer-like type eligible for `proxy` (see [*ProFacade* requirements](../ProFacade.md)). *Since 3.3.0*: If [`proxiable`](../proxiable.md) is `false`, the program is ill-formed and a diagnostic is generated.
+- `(4)` Let `VP` be `std::decay_t`. Sets the contained value to an object of type `VP`, direct-non-list-initialized with `std::forward
(ptr)`. Participates in overload resolution only if `VP` is not a specialization of `proxy` and is a pointer-like type eligible for `proxy` (see [*ProFacade* requirements](../ProFacade.md)). *Since 3.3.0*: If [`proxiable`](../proxiable.md) is `false`, the program is ill-formed and a diagnostic is generated.
## Return Value
diff --git a/docs/spec/proxy/constructor.md b/docs/spec/proxy/constructor.md
index 61f9182..922bf8f 100644
--- a/docs/spec/proxy/constructor.md
+++ b/docs/spec/proxy/constructor.md
@@ -44,7 +44,7 @@ Creates a new `proxy`.
- `(1)` Default constructor and the constructor taking `nullptr` construct a `proxy` that does not contain a value.
- `(2)` Copy constructor constructs a `proxy` whose contained value is that of `rhs` if `rhs` contains a value, or otherwise, constructs a `proxy` that does not contain a value. As per the `requires` clause, the copy constructor is trivial when `F::copyability == constraint_level::trivial`.
- `(3)` Move constructor constructs a `proxy` whose contained value is that of `rhs` if `rhs` contains a value, or otherwise, constructs a `proxy` that does not contain a value. `rhs` is in a valid but unspecified state after move construction. As per the `requires` clause, the move constructor does not participate in overload resolution when `F::copyability == constraint_level::trivial`, so that a move construction falls back to the trivial copy constructor.
-- `(4)` Let `VP` be `std::decay_t`. Constructs a `proxy` whose contained value is of type `VP`, direct-non-list-initialized with `std::forward
(ptr)`. Participates in overload resolution only if `VP` is a pointer-like type eligible for `proxy` (see [*ProFacade* requirements](../ProFacade.md)).
+- `(4)` Let `VP` be `std::decay_t
`. Constructs a `proxy` whose contained value is of type `VP`, direct-non-list-initialized with `std::forward
(ptr)`. Participates in overload resolution only if `VP` is not a specialization of `proxy` and is a pointer-like type eligible for `proxy` (see [*ProFacade* requirements](../ProFacade.md)).
- `(5)` Constructs a `proxy` whose contained value is of type `P`, direct-non-list-initialized with `std::forward(args)...`. Participates in overload resolution only if `P` is a pointer-like type eligible for `proxy`.
- `(6)` Constructs a `proxy` whose contained value is of type `P`, direct-non-list-initialized with `il, std::forward(args)...`. Participates in overload resolution only if `P` is a pointer-like type eligible for `proxy`.
diff --git a/include/proxy/v4/proxy.h b/include/proxy/v4/proxy.h
index a3a1d9b..9f4ecd4 100644
--- a/include/proxy/v4/proxy.h
+++ b/include/proxy/v4/proxy.h
@@ -635,16 +635,17 @@ struct refl_accessor_traits
template
using refl_accessor_t = typename refl_accessor_traits::type;
-template
-struct ptr_traits : inapplicable_traits {};
-template
- requires((
- requires { *std::declval(); } ||
- requires { typename P::element_type; }) &&
- requires { typename std::pointer_traits
::element_type; })
-struct ptr_traits
: applicable_traits {};
-template
-struct ptr_traits> : inapplicable_traits {};
+template
+concept pointer_like = (std::is_pointer_v ||
+ requires { typename T::element_type; } || requires(T val) { *val; }) &&
+ requires { typename std::pointer_traits::element_type; };
+
+template class TT>
+struct specialization_traits : inapplicable_traits {};
+template class TT, class... Args>
+struct specialization_traits, TT> : applicable_traits {};
+template class TT>
+concept specialization_of = specialization_traits::applicable;
template
consteval bool diagnose_proxiable_size_too_large() {
@@ -912,7 +913,7 @@ add_qualifier_t, Q>
} // namespace details
template
-concept proxiable = facade && details::ptr_traits::applicable &&
+concept proxiable = facade && details::pointer_like &&
details::facade_traits::template applicable_ptr;
template
@@ -990,7 +991,8 @@ class proxy : public details::facade_traits::direct_accessor,
template
constexpr proxy(P&& ptr) noexcept(
std::is_nothrow_constructible_v, P>)
- requires(details::ptr_traits>::applicable &&
+ requires(!details::specialization_of, proxy> &&
+ details::pointer_like> &&
std::is_constructible_v, P>)
{
initialize>(std::forward(ptr));
@@ -998,8 +1000,7 @@ class proxy : public details::facade_traits::direct_accessor,
template
constexpr explicit proxy(std::in_place_type_t, Args&&... args) noexcept(
std::is_nothrow_constructible_v
)
- requires(details::ptr_traits
::applicable &&
- std::is_constructible_v
)
+ requires(details::pointer_like
&& std::is_constructible_v
)
{
initialize
(std::forward(args)...);
}
@@ -1009,7 +1010,7 @@ class proxy : public details::facade_traits::direct_accessor,
Args&&... args) noexcept(std::
is_nothrow_constructible_v<
P, std::initializer_list&, Args...>)
- requires(details::ptr_traits::applicable &&
+ requires(details::pointer_like
&&
std::is_constructible_v
&, Args...>)
{
initialize
(il, std::forward(args)...);
@@ -1060,7 +1061,8 @@ class proxy : public details::facade_traits::direct_accessor,
constexpr proxy& operator=(P&& ptr) noexcept(
std::is_nothrow_constructible_v, P> &&
F::destructibility >= constraint_level::nothrow)
- requires(details::ptr_traits>::applicable &&
+ requires(!details::specialization_of, proxy> &&
+ details::pointer_like> &&
std::is_constructible_v, P> &&
F::destructibility >= constraint_level::nontrivial)
{
@@ -1127,8 +1129,7 @@ class proxy : public details::facade_traits::direct_accessor,
constexpr P& emplace(Args&&... args) noexcept(
std::is_nothrow_constructible_v &&
F::destructibility >= constraint_level::nothrow)
- requires(details::ptr_traits
::applicable &&
- std::is_constructible_v
&&
+ requires(details::pointer_like
&& std::is_constructible_v
&&
F::destructibility >= constraint_level::nontrivial)
{
reset();
@@ -1138,7 +1139,7 @@ class proxy : public details::facade_traits::direct_accessor,
constexpr P& emplace(std::initializer_list il, Args&&... args) noexcept(
std::is_nothrow_constructible_v&, Args...> &&
F::destructibility >= constraint_level::nothrow)
- requires(details::ptr_traits
::applicable &&
+ requires(details::pointer_like
&&
std::is_constructible_v
&, Args...> &&
F::destructibility >= constraint_level::nontrivial)
{
@@ -1146,7 +1147,9 @@ class proxy : public details::facade_traits::direct_accessor,
return initialize(il, std::forward(args)...);
}
- friend void swap(proxy& lhs, proxy& rhs) noexcept(noexcept(lhs.swap(rhs))) {
+ friend void swap(proxy& lhs, proxy& rhs) noexcept(noexcept(lhs.swap(rhs)))
+ requires(requires { lhs.swap(rhs); })
+ {
lhs.swap(rhs);
}
friend bool operator==(const proxy& lhs, std::nullptr_t) noexcept {
@@ -1163,7 +1166,7 @@ class proxy : public details::facade_traits::direct_accessor,
return details::invoke_impl(p, std::forward(args)...);
}
template
- friend auto invoke(proxy&& p, Args&&... args) ->
+ friend auto invoke(proxy&& p, Args&&... args) ->
typename details::overload_traits::return_type {
return details::invoke_impl(std::move(p),
std::forward(args)...);
diff --git a/tests/proxy_traits_tests.cpp b/tests/proxy_traits_tests.cpp
index 0f092e6..ab593bd 100644
--- a/tests/proxy_traits_tests.cpp
+++ b/tests/proxy_traits_tests.cpp
@@ -498,4 +498,7 @@ static_assert(!std::is_constructible_v,
ProxyWrapperTemplate>);
static_assert(std::is_move_constructible_v>);
+// proxiable shall not reject a specialization of proxy.
+static_assert(pro::proxiable, DefaultFacade>);
+
} // namespace proxy_traits_tests_details