Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revise spec for version 3.2 #231

Merged
merged 2 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5)

project(msft_proxy VERSION 3.1.0 LANGUAGES CXX)
project(msft_proxy VERSION 3.2.0 LANGUAGES CXX)
add_library(msft_proxy INTERFACE)
target_compile_features(msft_proxy INTERFACE cxx_std_20)
target_include_directories(msft_proxy INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
Expand Down
94 changes: 73 additions & 21 deletions README.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/PRO_DEF_FREE_AS_MEM_DISPATCH.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Macro `PRO_DEF_FREE_AS_MEM_DISPATCH`

```cpp
#define PRO_DEF_FREE_AS_MEM_DISPATCH // see below
#define PRO_DEF_FREE_AS_MEM_DISPATCH // since 3.1, see below
```

Macro `PRO_DEF_FREE_AS_MEM_DISPATCH` defines dispatch types for free function expressions with accessibility via a member function. It supports two syntaxes:
Expand All @@ -21,7 +21,7 @@ PRO_DEF_FREE_AS_MEM_DISPATCH(dispatch_name, func_name, accessibility_func_name);
```cpp
struct dispatch_name {
template <class T, class... Args>
decltype(auto) operator()(T&& self, Args&&... args)
decltype(auto) operator()(T&& self, Args&&... args) const
noexcept(noexcept(func_name(std::forward<T>(self), std::forward<Args>(args)...)))
requires(requires { func_name(std::forward<T>(self), std::forward<Args>(args)...); }) {
return func_name(std::forward<T>(self), std::forward<Args>(args)...);
Expand Down
2 changes: 1 addition & 1 deletion docs/PRO_DEF_FREE_DISPATCH.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ PRO_DEF_FREE_DISPATCH(dispatch_name, func_name, accessibility_func_name);
```cpp
struct dispatch_name {
template <class T, class... Args>
decltype(auto) operator()(T&& self, Args&&... args)
decltype(auto) operator()(T&& self, Args&&... args) const
noexcept(noexcept(func_name(std::forward<T>(self), std::forward<Args>(args)...)))
requires(requires { func_name(std::forward<T>(self), std::forward<Args>(args)...); }) {
return func_name(std::forward<T>(self), std::forward<Args>(args)...);
Expand Down
2 changes: 1 addition & 1 deletion docs/PRO_DEF_MEM_DISPATCH.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ PRO_DEF_MEM_DISPATCH(dispatch_name, func_name, accessibility_func_name);
```cpp
struct dispatch_name {
template <class T, class... Args>
decltype(auto) operator()(T&& self, Args&&... args)
decltype(auto) operator()(T&& self, Args&&... args) const
noexcept(noexcept(std::forward<T>(self).func_name(std::forward<Args>(args)...)))
requires(requires { std::forward<T>(self).func_name(std::forward<Args>(args)...); }) {
return std::forward<T>(self).func_name(std::forward<Args>(args)...);
Expand Down
7 changes: 5 additions & 2 deletions docs/PRO_DEF_WEAK_DISPATCH.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# Macro `PRO_DEF_WEAK_DISPATCH`

```cpp
#define PRO_DEF_WEAK_DISPATCH // see below
#define PRO_DEF_WEAK_DISPATCH // deprecated since 3.2, see below
```

<mark>⚠️ Macro `PRO_DEF_WEAK_DISPATCH` has been replaced by class template `weak_dispatch` since 3.2, and may be removed in a future version.</mark>

Macro `PRO_DEF_WEAK_DISPATCH` defines a "weak dispatch" type with a default implementation. It supports the following syntax:

```cpp
Expand All @@ -16,7 +18,7 @@ Defines a class named `dispatch_name` that inherits `existing_dispatch` and prov
struct dispatch_name : existing_dispatch {
using existing_dispatch::operator();
template <class... Args>
decltype(auto) operator()(std::nullptr_t, Args&&... args)
decltype(auto) operator()(std::nullptr_t, Args&&... args) const
noexcept(noexcept(default_func_name(std::forward<Args>(args)...)))
requires(requires { default_func_name(std::forward<Args>(args)...); }) {
return default_func_name(std::forward<Args>(args)...);
Expand Down Expand Up @@ -68,4 +70,5 @@ int main() {

## See Also

- [class template `weak_dispatch`](weak_dispatch.md)
- [named requirements *ProDispatch*](ProDispatch.md)
2 changes: 1 addition & 1 deletion docs/ProOverload.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ A type `O` meets the *ProOverload* requirements if it matches one of the followi
| `R(Args...) && noexcept` |
| `R(Args...) const` |
| `R(Args...) const noexcept` |
| `R(Args...) cosnt&` |
| `R(Args...) const&` |
| `R(Args...) const& noexcept` |
| `R(Args...) const&&` |
| `R(Args...) const&& noexcept` |
Expand Down
2 changes: 1 addition & 1 deletion docs/access_proxy.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Accesses a `proxy` object from an [accessor](ProAccessible.md) instantiated from

## Return Value

A reference to the `proxy` that instantiates `a`.
A reference to the `proxy` that has instantiated `a`.

## Notes

Expand Down
15 changes: 15 additions & 0 deletions docs/bad_proxy_cast.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Class `bad_proxy_cast`

```cpp
class bad_proxy_cast : public std::bad_cast;
```

A type of object to be thrown by the value-returning forms of [`proxy_cast`](basic_facade_builder/support_rtti.md) on failure.

## Member Functions

| Name | Description |
| ------------- | ------------------------------------ |
| (constructor) | constructs a `bad_proxy_cast` object |
| (destructor) | destroys a `bad_proxy_cast` object |
| `what` | returns the explanatory string |
70 changes: 65 additions & 5 deletions docs/basic_facade_builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,83 @@ using facade_builder = basic_facade_builder<std::tuple<>, std::tuple<>,

`class Cs`, `class Rs`, and `proxiable_ptr_constraints C` are the template parameters of `basic_facade_builder`. `basic_facade_builder` provides a member type `build` that compiles the template parameters into a [`facade`](facade.md) type. The template parameters can be modified via various member alias templates that specify `basic_facade_builder` with the modified template parameters.

## Notes

The design of `basic_facade_builder` utilizes template metaprogramming techniques. We recommend the following 2 guidelines when using `basic_facade_builder` to define a facade type.

- **Define a type for each facade.**

For example, when defining a `Formattable` facade, the following two definitions are both syntactically correct:

```cpp
// (1) Recommended
struct Formattable : pro::facade_builder
::support_format
::build {};

// (2) Discouraged
using Formattable = pro::facade_builder
::support_format
::build;
```

Definition `(2)` is a type alias, its "real" type may have a long name, and the type evaluation may be executed for multiple times even when compiling a single source file. Although the two type definitions are equivalent at runtime, definitions like `(2)` may significantly reduce compilation performance. Therefore, it is recommended always to define a facade as a type with inheritance, similar to definition `(1)`.

- **Use the `template` keyword on demand when defining a facade template.**

Consider the following facade template definitions:

```cpp
template <class... Os>
struct MovableCallable : pro::facade_builder
::add_convention<pro::operator_dispatch<"()">, Os...>
::build {};

template <class... Os>
struct CopyableCallable : pro::facade_builder
::add_facade<MovableCallable<Os...>>
::support_copy<pro::constraint_level::nontrivial>
::build {};
```

Although GCC can usually compile the code above, it does not adhere to the C++ standard syntax, and as a result, it won't compile with Clang or MSVC ([live demo](https://godbolt.org/z/Gen74qY9r)). This is because type `add_facade<MovableCallable<Os...>>` depends on the template parameters, and an explicit `template` is required when specifying its member alias template `support_copy`. To fix the code, we could either add the keyword `template` before `support_copy`, or simply swap `add_facade` and `support_copy`. For instance:

```cpp
template <class... Os>
struct CopyableCallable : pro::facade_builder
::add_facade<MovableCallable<Os...>>
::template support_copy<pro::constraint_level::nontrivial>
::build {};

// Or

template <class... Os>
struct CopyableCallable : pro::facade_builder
::support_copy<pro::constraint_level::nontrivial>
::add_facade<MovableCallable<Os...>>
::build {};
```

## Member Types

| Name | Description |
| ---------------------------------------- | ------------------------------------------------------------ |
| [`build`](basic_facade_builder/build.md) | Specifies a [`facade`](facade.md) type deduced from the template parameters of the `basic_facade_builder` |
| Name | Description |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| [`build`](basic_facade_builder/build.md) | Specifies a [`facade`](facade.md) type deduced from the template parameters of the `basic_facade_builder` |
| [`support_format`<br />`support_wformat`](basic_facade_builder/support_format.md)<br />*(since 3.2)* | Specifies the capability of formatting (via [formatting functions](https://en.cppreference.com/w/cpp/utility/format)) to the template parameters |
| [`support_rtti`<br />`support_indirect_rtti`<br />`support_direct_rtti`](basic_facade_builder/support_rtti.md)<br />*(since 3.2)* | Specifies the capability of RTTI (via `proxy_cast` and `proxy_typeid`) to the template parameters |

## Member Alias Templates

| Name | Description |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| [`add_convention`<br />`add_indirect_convention`<br />`add_direct_convention`](basic_facade_builder/add_convention.md) | Adds a convention to the template parameters |
| [`add_reflection`<br />`add_indirect_reflection`<br />`add_direct_reflection`](basic_facade_builder/add_reflection.md) | Adds a reflection to the template parameters |
| [`add_facade`](basic_facade_builder/add_facade.md) | Adds a facade to the template parameters |
| [`add_reflection`<br />`add_indirect_reflection`<br />`add_direct_reflection`](basic_facade_builder/add_reflection.md) | Adds a reflection to the template parameters |
| [`add_view` ](basic_facade_builder/support_view.md)<br />*(since 3.2)* | Specifies the capability of implicit conversion to `proxy_view` to the template parameters |
| [`restrict_layout`](basic_facade_builder/restrict_layout.md) | Specifies maximum `max_size` and `max_align` of `C` in the template parameters |
| [`support_copy`](basic_facade_builder/support_copy.md) | Specifies minimum `copyability` of `C` in the template parameters |
| [`support_relocation`](basic_facade_builder/support_relocation.md) | Specifies minimum `relocatability` of `C` in the template parameters |
| [`support_destruction`](basic_facade_builder/support_destruction.md) | Specifies minimum `destructibility` of `C` in the template parameters |
| [`support_relocation`](basic_facade_builder/support_relocation.md) | Specifies minimum `relocatability` of `C` in the template parameters |

## Member Functions

Expand Down
4 changes: 2 additions & 2 deletions docs/basic_facade_builder/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using build = /* see below */;
```

Specifies a [facade](facade.md) type deduced from the template parameters of `basic_facade_builder<Cs, Rs, C>`. Specifically,
Specifies a [facade](../facade.md) type deduced from the template parameters of `basic_facade_builder<Cs, Rs, C>`. Specifically,

- `typename build::convention_types` is defined as `Cs`, and
- `typename build::reflection_types` is defined as `Rs`, and
Expand Down Expand Up @@ -50,7 +50,7 @@ consteval proxiable_ptr_constraints normalize(proxiable_ptr_constraints value) {

It is encouraged to inherit `build` with an empty `struct` before specifying a [`proxy`](../proxy.md), rather than `using` or `typedef` the `build` type into an alias, to improve compilation performance.

The default values of the fields of [`proxiable_ptr_constraints`](../proxiable_ptr_constraints.md) are based on our engineering practices. The default values of `max_size` and `max_alignment` are usually sufficient for many implementations of [fancy pointers](https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers), such as [`std::unique_ptr`](https://en.cppreference.com/w/cpp/memory/unique_ptr), [`std::shared_ptr`](https://en.cppreference.com/w/cpp/memory/shared_ptr), and [boost::interprocess::offset_ptr](https://www.boost.org/doc/libs/1_85_0/doc/html/interprocess/offset_ptr.html). A larger combination of size and alignment ensures better compatibility with the implementation of the underlying pointers and reduces heap allocation when the element type fits in the buffer (see [function template `make_proxy`](../make_proxy.md)), at the cost of making the corresponding [`proxy`](../proxy.md) objects larger.
The default values of the fields of [`proxiable_ptr_constraints`](../proxiable_ptr_constraints.md) are based on our engineering practices. The default values of `max_size` and `max_alignment` are usually sufficient for many implementations of [fancy pointers](https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers), such as [`std::unique_ptr`](https://en.cppreference.com/w/cpp/memory/unique_ptr), [`std::shared_ptr`](https://en.cppreference.com/w/cpp/memory/shared_ptr), and [`boost::interprocess::offset_ptr`](https://www.boost.org/doc/libs/1_85_0/doc/html/interprocess/offset_ptr.html). A larger combination of size and alignment ensures better compatibility with the implementation of the underlying pointers and reduces heap allocation when the element type fits in the buffer (see [function template `make_proxy`](../make_proxy.md)), at the cost of making the corresponding [`proxy`](../proxy.md) objects larger.

## Example

Expand Down
34 changes: 34 additions & 0 deletions docs/basic_facade_builder/support_format.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# `basic_facade_builder::support_format`<br />`basic_facade_builder::support_wformat`

```cpp
using support_format = basic_facade_builder</* see below */>;

using support_wformat = basic_facade_builder</* see below */>;
```

The member types `support_format` and `support_wformat` of `basic_facade_builder<Cs, Rs, C>` add necessary convention and reflection types to the template parameters, enabling specializations of [`std::formatter<proxy_indirect_accessor<F>, CharT>`](../formatter_proxy_indirect_accessor.md) where `F` is a [facade](../facade.md) type built from `basic_facade_builder`, `CharT` is `char` (if `support_format` is specified) or `wchar_t` (if `support_wformat` is specified).

`support_format` and `support_wformat` also add constraints to a facade type `F` built from `basic_facade_builder`, requiring a contained value of `proxy<F>` be *formattable*. Formally, let `p` be a contained value of `proxy<F>`, `CharT` be `char` (if `support_format` is specified) or `wchar_t` (if `support_wformat` is specified), `T` be `std::decay_t<decltype(*std::as_const(p))>`, `std::formatter<T, CharT>` shall be an enabled specialization of `std::formatter`.

## Example

```cpp
#include <format>
#include <iostream>

#include "proxy.h"

struct Formattable : pro::facade_builder
::support_format
::build {};

int main() {
pro::proxy<Formattable> p = pro::make_proxy<Formattable>(123);
std::cout << std::format("{}", *p) << "\n"; // Prints: "123"
std::cout << std::format("{:*<6}", *p) << "\n"; // Prints: "123***"
}
```

## See Also

- [class template `std::formatter<proxy_indirect_accessor>`](../formatter_proxy_indirect_accessor.md)
44 changes: 44 additions & 0 deletions docs/basic_facade_builder/support_rtti.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# `basic_facade_builder::support_rtti`<br />`basic_facade_builder::support_indirect_rtti`<br />`basic_facade_builder::support_direct_rtti`

```cpp
using support_rtti = support_indirect_rtti;

using support_indirect_rtti = basic_facade_builder</* see below */>;

using support_direct_rtti = basic_facade_builder</* see below */>;
```

The member types `support_rtti`, `support_indirect_rtti` and `support_direct_rtti` add necessary convention and reflection types to the template parameters, enabling [RTTI](https://en.wikipedia.org/wiki/Run-time_type_information) support for [`proxy<F>`](../proxy.md), where `F` is a [facade](../facade.md) type built from `basic_facade_builder`. For an RTTI-enabled facade `F`, non-member functions `proxy_typeid` (similar to [`std::any::type`](https://en.cppreference.com/w/cpp/utility/any/type)) and `proxy_cast` (similar to [`std::any_cast`](https://en.cppreference.com/w/cpp/utility/any/any_cast)) are available for [`proxy_indirect_accessor<F>`](../proxy_indirect_accessor.md) (if `support_rtti` or `support_indirect_rtti` is specified) or [`proxy<F>`](../proxy.md) (if `support_direct_rtti` is specified).

## Non-Member Functions

| Name | Description |
| ---------------------------------------------- | ------------------------------------------ |
| [`proxy_typeid`](support_rtti/proxy_typeid.md) | returns the `typeid` of the contained type |
| [`proxy_cast`](support_rtti/proxy_cast.md) | type-safe access to the contained object |

## Example

```cpp
#include <iostream>

#include "proxy.h"

struct RttiAware : pro::facade_builder
::support_rtti
::support_direct_rtti
::build {};

int main() {
int v = 123;
pro::proxy<RttiAware> p = &v;
std::cout << proxy_typeid(p).name() << "\n"; // Prints: "Pi" (assuming GCC)
std::cout << proxy_cast<int*>(p) << "\n"; // Prints the address of v
std::cout << proxy_typeid(*p).name() << "\n"; // Prints: "i" (assuming GCC)
std::cout << proxy_cast<int>(*p) << "\n"; // Prints: "123"
}
```

## See Also

- [`support_view`](support_view.md)
Loading