Skip to content

Commit

Permalink
Revise spec for version 3.2 (#231)
Browse files Browse the repository at this point in the history
  • Loading branch information
mingxwa authored Jan 23, 2025
1 parent f34bb8f commit f220768
Show file tree
Hide file tree
Showing 44 changed files with 868 additions and 135 deletions.
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

0 comments on commit f220768

Please sign in to comment.