Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/spec/ProFacade.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ 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<P&>(); } || requires { typename P::element_type; }) &&
Expand Down
2 changes: 1 addition & 1 deletion docs/spec/proxy/assignment.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<P>`. Sets the contained value to an object of type `VP`, direct-non-list-initialized with `std::forward<P>(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<VP, F>`](../proxiable.md) is `false`, the program is ill-formed and a diagnostic is generated.
- `(4)` Let `VP` be `std::decay_t<P>`. Sets the contained value to an object of type `VP`, direct-non-list-initialized with `std::forward<P>(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<VP, F>`](../proxiable.md) is `false`, the program is ill-formed and a diagnostic is generated.

## Return Value

Expand Down
2 changes: 1 addition & 1 deletion docs/spec/proxy/constructor.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<P>`. Constructs a `proxy` whose contained value is of type `VP`, direct-non-list-initialized with `std::forward<P>(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<P>`. Constructs a `proxy` whose contained value is of type `VP`, direct-non-list-initialized with `std::forward<P>(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>(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>(args)...`. Participates in overload resolution only if `P` is a pointer-like type eligible for `proxy`.

Expand Down
45 changes: 24 additions & 21 deletions include/proxy/v4/proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -635,16 +635,17 @@ struct refl_accessor_traits<R, F, true>
template <class R, class F, bool IsDirect>
using refl_accessor_t = typename refl_accessor_traits<R, F, IsDirect>::type;

template <class P>
struct ptr_traits : inapplicable_traits {};
template <class P>
requires((
requires { *std::declval<P&>(); } ||
requires { typename P::element_type; }) &&
requires { typename std::pointer_traits<P>::element_type; })
struct ptr_traits<P> : applicable_traits {};
template <class F>
struct ptr_traits<proxy<F>> : inapplicable_traits {};
template <class T>
concept pointer_like = (requires { *std::declval<T&>(); } ||
requires { typename T::element_type; }) &&
requires { typename std::pointer_traits<T>::element_type; };

template <class T, template <class...> class TT>
struct specialization_traits : inapplicable_traits {};
template <template <class...> class TT, class... Args>
struct specialization_traits<TT<Args...>, TT> : applicable_traits {};
template <class T, template <class...> class TT>
concept specialization_of = specialization_traits<T, TT>::applicable;

template <class P, class F, std::size_t ActualSize, std::size_t MaxSize>
consteval bool diagnose_proxiable_size_too_large() {
Expand Down Expand Up @@ -912,7 +913,7 @@ add_qualifier_t<proxy<F>, Q>
} // namespace details

template <class P, class F>
concept proxiable = facade<F> && details::ptr_traits<P>::applicable &&
concept proxiable = facade<F> && details::pointer_like<P> &&
details::facade_traits<F>::template applicable_ptr<P>;

template <facade F>
Expand Down Expand Up @@ -990,16 +991,16 @@ class proxy : public details::facade_traits<F>::direct_accessor,
template <class P>
constexpr proxy(P&& ptr) noexcept(
std::is_nothrow_constructible_v<std::decay_t<P>, P>)
requires(details::ptr_traits<std::decay_t<P>>::applicable &&
requires(!details::specialization_of<std::decay_t<P>, proxy> &&
details::pointer_like<std::decay_t<P>> &&
std::is_constructible_v<std::decay_t<P>, P>)
{
initialize<std::decay_t<P>>(std::forward<P>(ptr));
}
template <class P, class... Args>
constexpr explicit proxy(std::in_place_type_t<P>, Args&&... args) noexcept(
std::is_nothrow_constructible_v<P, Args...>)
requires(details::ptr_traits<P>::applicable &&
std::is_constructible_v<P, Args...>)
requires(details::pointer_like<P> && std::is_constructible_v<P, Args...>)
{
initialize<P>(std::forward<Args>(args)...);
}
Expand All @@ -1009,7 +1010,7 @@ class proxy : public details::facade_traits<F>::direct_accessor,
Args&&... args) noexcept(std::
is_nothrow_constructible_v<
P, std::initializer_list<U>&, Args...>)
requires(details::ptr_traits<P>::applicable &&
requires(details::pointer_like<P> &&
std::is_constructible_v<P, std::initializer_list<U>&, Args...>)
{
initialize<P>(il, std::forward<Args>(args)...);
Expand Down Expand Up @@ -1060,7 +1061,8 @@ class proxy : public details::facade_traits<F>::direct_accessor,
constexpr proxy& operator=(P&& ptr) noexcept(
std::is_nothrow_constructible_v<std::decay_t<P>, P> &&
F::destructibility >= constraint_level::nothrow)
requires(details::ptr_traits<std::decay_t<P>>::applicable &&
requires(!details::specialization_of<std::decay_t<P>, proxy> &&
details::pointer_like<std::decay_t<P>> &&
std::is_constructible_v<std::decay_t<P>, P> &&
F::destructibility >= constraint_level::nontrivial)
{
Expand Down Expand Up @@ -1127,8 +1129,7 @@ class proxy : public details::facade_traits<F>::direct_accessor,
constexpr P& emplace(Args&&... args) noexcept(
std::is_nothrow_constructible_v<P, Args...> &&
F::destructibility >= constraint_level::nothrow)
requires(details::ptr_traits<P>::applicable &&
std::is_constructible_v<P, Args...> &&
requires(details::pointer_like<P> && std::is_constructible_v<P, Args...> &&
F::destructibility >= constraint_level::nontrivial)
{
reset();
Expand All @@ -1138,15 +1139,17 @@ class proxy : public details::facade_traits<F>::direct_accessor,
constexpr P& emplace(std::initializer_list<U> il, Args&&... args) noexcept(
std::is_nothrow_constructible_v<P, std::initializer_list<U>&, Args...> &&
F::destructibility >= constraint_level::nothrow)
requires(details::ptr_traits<P>::applicable &&
requires(details::pointer_like<P> &&
std::is_constructible_v<P, std::initializer_list<U>&, Args...> &&
F::destructibility >= constraint_level::nontrivial)
{
reset();
return initialize<P>(il, std::forward<Args>(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 {
Expand All @@ -1163,7 +1166,7 @@ class proxy : public details::facade_traits<F>::direct_accessor,
return details::invoke_impl<F, true, D, O>(p, std::forward<Args>(args)...);
}
template <class D, class O, class... Args>
friend auto invoke(proxy<F>&& p, Args&&... args) ->
friend auto invoke(proxy&& p, Args&&... args) ->
typename details::overload_traits<O>::return_type {
return details::invoke_impl<F, true, D, O>(std::move(p),
std::forward<Args>(args)...);
Expand Down
3 changes: 3 additions & 0 deletions tests/proxy_traits_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,4 +498,7 @@ static_assert(!std::is_constructible_v<pro::proxy<DefaultFacade>,
ProxyWrapperTemplate<void>>);
static_assert(std::is_move_constructible_v<ProxyWrapperTemplate<void>>);

// proxiable shall not reject a specialization of proxy.
static_assert(pro::proxiable<pro::proxy_view<DefaultFacade>, DefaultFacade>);

} // namespace proxy_traits_tests_details
Loading