diff --git a/docs/spec/.pages b/docs/spec/.pages index 2b6247c..7c25ed0 100644 --- a/docs/spec/.pages +++ b/docs/spec/.pages @@ -32,6 +32,7 @@ nav: - allocate_proxy_shared: allocate_proxy_shared.md - allocate_proxy: allocate_proxy.md - make_proxy_inplace: make_proxy_inplace.md + - make_proxy_observed: make_proxy_observed.md - make_proxy_shared: make_proxy_shared.md - make_proxy_view: make_proxy_view.md - make_proxy: make_proxy.md diff --git a/docs/spec/README.md b/docs/spec/README.md index 255903e..ea0113c 100644 --- a/docs/spec/README.md +++ b/docs/spec/README.md @@ -52,6 +52,7 @@ This document provides the API specifications for the C++ library Proxy (version | [`allocate_proxy_shared`](allocate_proxy_shared.md) | Creates a `proxy` object with shared ownership using an allocator | | [`allocate_proxy`](allocate_proxy.md) | Creates a `proxy` object with an allocator | | [`make_proxy_inplace`](make_proxy_inplace.md) | Creates a `proxy` object with strong no-allocation guarantee | +| [`make_proxy_observed`](make_proxy_observed.md) | Creates a `proxy` object with no ownership | | [`make_proxy_shared`](make_proxy_shared.md) | Creates a `proxy` object with shared ownership | | [`make_proxy_view`](make_proxy_view.md) | Creates a `proxy_view` object | | [`make_proxy`](make_proxy.md) | Creates a `proxy` object potentially with heap allocation | diff --git a/docs/spec/make_proxy_observed.md b/docs/spec/make_proxy_observed.md new file mode 100644 index 0000000..6b97a2c --- /dev/null +++ b/docs/spec/make_proxy_observed.md @@ -0,0 +1,50 @@ +# Function template `make_proxy_observed` + +> Header: `proxy.h` +> Module: `proxy` +> Namespace: `pro::inline v4` +> Since: 4.1.0 + +The definition of `make_proxy_observed` makes use of an exposition-only class template *observer-ptr*. `observer-ptr` contains a raw pointer to an object of type `T`, and provides `operator*` for access with the same qualifiers. + +```cpp +template +proxy make_proxy_observed(T& value) noexcept; +``` + +Creates a `proxy` object containing a value `p` of type `observer-ptr`, where `*p` is direct-non-list-initialized with `std::addressof(value)`. If [`proxiable_target`](proxiable_target.md) is `false`, the program is ill-formed and diagnostic messages are generated. + +## Return Value + +The constructed `proxy` object. + +## Example + +```cpp +#include + +#include + +struct Printable : pro::facade_builder // + ::add_convention, + std::ostream&(std::ostream&) const> // + ::build {}; + +int main() { + int val = 123; + pro::proxy p = pro::make_proxy_observed(val); + + // Prints "123" + std::cout << *p << "\n"; + + val = 456; + + // Prints "456" + std::cout << *p << "\n"; +} +``` + +## See Also + +- [concept `proxiable_target`](proxiable_target.md) +- [function template `make_proxy_view`](make_proxy_view.md) \ No newline at end of file diff --git a/docs/spec/make_proxy_view.md b/docs/spec/make_proxy_view.md index d70b61a..22e0571 100644 --- a/docs/spec/make_proxy_view.md +++ b/docs/spec/make_proxy_view.md @@ -5,14 +5,12 @@ > Namespace: `pro::inline v4` > Since: 3.3.0 -The definition of `make_proxy_view` makes use of an exposition-only class template *observer-ptr*. `observer-ptr` contains a raw pointer to an object of type `T`, and provides `operator*` for access with the same qualifiers. - ```cpp template proxy_view make_proxy_view(T& value) noexcept; ``` -Creates a `proxy_view` object containing a value `p` of type `observer-ptr`, where `*p` is direct-non-list-initialized with `&value`. If [`proxiable_target`](proxiable_target.md) is `false`, the program is ill-formed and diagnostic messages are generated. +Equivalent to `return make_proxy_observed>(value)`. ## Return Value diff --git a/docs/spec/proxiable_target.md b/docs/spec/proxiable_target.md index 403bc55..b538a7a 100644 --- a/docs/spec/proxiable_target.md +++ b/docs/spec/proxiable_target.md @@ -7,10 +7,10 @@ ```cpp template -concept proxiable_target = proxiable, F>; +concept proxiable_target = proxiable, observer_facade>; ``` -See [`make_proxy_view`](make_proxy_view.md) for the definition of the exposition-only class template *observer-ptr*. +See [`make_proxy_observed`](make_proxy_observed.md) for the definition of the exposition-only class template *observer-ptr*. ## Example diff --git a/docs/spec/skills_as_view.md b/docs/spec/skills_as_view.md index aafe7a3..9131df9 100644 --- a/docs/spec/skills_as_view.md +++ b/docs/spec/skills_as_view.md @@ -12,7 +12,7 @@ using as_view = /* see below */; The alias template `as_view` modifies a specialization of [`basic_facade_builder`](basic_facade_builder/README.md) to allow implicit conversion from [`proxy`](proxy/README.md)`` to [`proxy_view`](proxy_view.md)``, where `F` is a built [facade](facade.md) type. -Let `p` be a value of type `proxy`, `ptr` be the contained value of `p` (if any), the conversion from type `proxy&` to type `proxy_view` is equivalent to `return observer-ptr{std::addressof(*ptr)}` if `p` contains a value, or otherwise equivalent to `return nullptr`. `observer-ptr` is an exposition-only type that `*observer-ptr`, `*std::as_const(observer-ptr)`, `*std::move(observer-ptr)` and `*std::move(std::as_const(observer-ptr))` are equivalent to `*ptr`, `*std::as_const(ptr)`, `*std::move(ptr)` and `*std::move(std::as_const(ptr))`, respectively. +Let `p` be a value of type `proxy`, `ptr` be the contained value of `p` (if any), the conversion from type `proxy&` to type `proxy_view` is equivalent to `return make_proxy_view(*ptr)` if `p` contains a value, or otherwise equivalent to `return nullptr`. ## Notes diff --git a/include/proxy/v4/proxy.h b/include/proxy/v4/proxy.h index ae9903f..1c21a64 100644 --- a/include/proxy/v4/proxy.h +++ b/include/proxy/v4/proxy.h @@ -1818,10 +1818,14 @@ constexpr proxy make_proxy_inplace(T&& value) noexcept( std::in_place, std::forward(value)}; } +template +constexpr proxy make_proxy_observed(T& value) noexcept { + return proxy{details::observer_ptr{value}}; +} + template constexpr proxy_view make_proxy_view(T& value) noexcept { - return proxy_view{ - details::observer_ptr{value}}; + return make_proxy_observed>(value); } #if __STDC_HOSTED__ diff --git a/include/proxy/v4/proxy.ixx b/include/proxy/v4/proxy.ixx index 37fb981..65614ba 100644 --- a/include/proxy/v4/proxy.ixx +++ b/include/proxy/v4/proxy.ixx @@ -22,6 +22,7 @@ using v4::is_bitwise_trivially_relocatable; using v4::is_bitwise_trivially_relocatable_v; using v4::make_proxy; using v4::make_proxy_inplace; +using v4::make_proxy_observed; using v4::make_proxy_shared; using v4::make_proxy_view; using v4::not_implemented; diff --git a/tests/proxy_creation_tests.cpp b/tests/proxy_creation_tests.cpp index d88dc24..b49e860 100644 --- a/tests/proxy_creation_tests.cpp +++ b/tests/proxy_creation_tests.cpp @@ -174,6 +174,7 @@ struct TestWeakSharedStringable : pro::facade_builder // static_assert(pro::proxiable); static_assert(!pro::proxiable); +static_assert(pro::proxiable_target); } // namespace proxy_creation_tests_details @@ -1222,3 +1223,28 @@ TEST(ProxyCreationTests, TestMakeProxyView) { p = pro::make_proxy_view(test_callable); ASSERT_EQ((*std::move(std::as_const(p)))(), 3); } + +TEST(ProxyCreationTests, TestMakeProxyObserved) { + struct TestFacade + : pro::facade_builder // + ::add_convention, int() &, int() const&, + int() && noexcept, int() const&&> // + ::build {}; + + struct { + int operator()() & noexcept { return 0; } + int operator()() const& noexcept { return 1; } + int operator()() && noexcept { return 2; } + int operator()() const&& noexcept { return 3; } + } test_callable; + + pro::proxy p = + pro::make_proxy_observed(test_callable); + static_assert(!noexcept((*p)())); + static_assert(noexcept((*std::move(p))())); + ASSERT_EQ((*p)(), 0); + ASSERT_EQ((*std::as_const(p))(), 1); + ASSERT_EQ((*std::move(p))(), 2); + p = pro::make_proxy_observed(test_callable); + ASSERT_EQ((*std::move(std::as_const(p)))(), 3); +}