├── .gitattributes ├── .github └── workflows │ ├── bvt-appleclang.yml │ ├── bvt-clang.yml │ ├── bvt-compatibility.yml │ ├── bvt-gcc.yml │ ├── bvt-msvc.yml │ ├── bvt-nvhpc.yml │ ├── bvt-report.yml │ ├── pipeline-ci.yml │ └── pipeline-release.yml ├── .gitignore ├── CMakeLists.txt ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── SECURITY.md ├── SUPPORT.md ├── benchmarks ├── CMakeLists.txt ├── proxy_invocation_benchmark.cpp ├── proxy_invocation_benchmark_context.cpp ├── proxy_invocation_benchmark_context.h └── proxy_management_benchmark.cpp ├── cmake ├── proxyConfig.cmake.in └── proxyModuleTargets.cmake ├── docs ├── CMakeLists.txt ├── PRO_DEF_FREE_AS_MEM_DISPATCH.md ├── PRO_DEF_FREE_DISPATCH.md ├── PRO_DEF_MEM_DISPATCH.md ├── ProAccessible.md ├── ProBasicConvention.md ├── ProBasicFacade.md ├── ProBasicReflection.md ├── ProConvention.md ├── ProDispatch.md ├── ProFacade.md ├── ProOverload.md ├── ProReflection.md ├── access_proxy.md ├── allocate_proxy.md ├── allocate_proxy_shared.md ├── bad_proxy_cast.md ├── basic_facade_builder.md ├── basic_facade_builder │ ├── add_convention.md │ ├── add_facade.md │ ├── add_reflection.md │ ├── build.md │ ├── restrict_layout.md │ ├── support_copy.md │ ├── support_destruction.md │ ├── support_format.md │ ├── support_relocation.md │ ├── support_rtti.md │ ├── support_rtti │ │ ├── proxy_cast.md │ │ └── proxy_typeid.md │ ├── support_view.md │ └── support_weak.md ├── constraint_level.md ├── cpp20_modules_support.md ├── explicit_conversion_dispatch.md ├── explicit_conversion_dispatch │ ├── accessor.md │ └── operator_call.md ├── facade.md ├── facade_aware_overload_t.md ├── faq.md ├── formatter_proxy_indirect_accessor.md ├── formatter_proxy_indirect_accessor │ ├── format.md │ └── parse.md ├── implicit_conversion_dispatch.md ├── implicit_conversion_dispatch │ ├── accessor.md │ └── operator_call.md ├── inplace_proxiable_target.md ├── make_proxy.md ├── make_proxy_inplace.md ├── make_proxy_shared.md ├── make_proxy_view.md ├── msft_lib_proxy.md ├── not_implemented.md ├── operator_dispatch.md ├── operator_dispatch │ ├── accessor.md │ └── operator_call.md ├── proxiable.md ├── proxiable_ptr_constraints.md ├── proxiable_target.md ├── proxy.md ├── proxy │ ├── assignment.md │ ├── constructor.md │ ├── destructor.md │ ├── emplace.md │ ├── friend_operator_equality.md │ ├── friend_swap.md │ ├── indirection.md │ ├── operator_bool.md │ ├── reset.md │ └── swap.md ├── proxy_indirect_accessor.md ├── proxy_invoke.md ├── proxy_reflect.md ├── proxy_view.md ├── specifications.md ├── weak_dispatch.md ├── weak_dispatch │ └── operator_call.md └── weak_proxy.md ├── include └── proxy │ ├── proxy.h │ ├── proxy.ixx │ ├── proxy_fmt.h │ └── proxy_macros.h ├── tests ├── CMakeLists.txt ├── cpp20_modules │ ├── CMakeLists.txt │ ├── foo.cpp │ ├── impl.cpp │ └── main.cpp ├── freestanding │ └── proxy_freestanding_tests.cpp ├── proxy_creation_tests.cpp ├── proxy_dispatch_tests.cpp ├── proxy_fmt_format_tests.cpp ├── proxy_format_tests.cpp ├── proxy_integration_tests.cpp ├── proxy_invocation_tests.cpp ├── proxy_lifetime_tests.cpp ├── proxy_reflection_tests.cpp ├── proxy_regression_tests.cpp ├── proxy_rtti_tests.cpp ├── proxy_traits_tests.cpp ├── proxy_view_tests.cpp └── utils.h └── tools ├── dump_build_env.sh ├── dump_build_env_msvc.ps1 ├── extract_example_code_from_docs.py └── report_generator ├── CMakeLists.txt ├── main.cpp └── report-config.json /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.github/workflows/bvt-appleclang.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | branch: 5 | type: string 6 | required: false 7 | 8 | jobs: 9 | bvt-appleclang: 10 | runs-on: macos-15 11 | steps: 12 | - uses: actions/checkout@v4 13 | with: 14 | ref: ${{ inputs.branch }} 15 | 16 | - name: check compiler versions 17 | run: | 18 | clang --version 19 | xcodebuild -version 20 | 21 | - name: build and run test with AppleClang 22 | run: | 23 | cmake -B build -GNinja -DCMAKE_CXX_STANDARD=23 -DCMAKE_BUILD_TYPE=Release -DPROXY_BUILD_MODULES=FALSE 24 | cmake --build build -j 25 | ctest --test-dir build -j 26 | mkdir build/drop 27 | chmod +x tools/dump_build_env.sh 28 | ./tools/dump_build_env.sh clang++ build/drop/env-info.json 29 | 30 | - name: run benchmarks 31 | run: | 32 | build/benchmarks/msft_proxy_benchmarks --benchmark_min_warmup_time=0.1 --benchmark_min_time=0.1s --benchmark_repetitions=30 --benchmark_enable_random_interleaving=true --benchmark_report_aggregates_only=true --benchmark_format=json > build/drop/benchmarking-results.json 33 | 34 | - name: archive benchmarking results 35 | uses: actions/upload-artifact@v4 36 | with: 37 | name: drop-appleclang 38 | path: build/drop/ 39 | -------------------------------------------------------------------------------- /.github/workflows/bvt-clang.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | branch: 5 | type: string 6 | required: false 7 | 8 | jobs: 9 | bvt-clang: 10 | runs-on: ubuntu-24.04 11 | steps: 12 | - uses: actions/checkout@v4 13 | with: 14 | ref: ${{ inputs.branch }} 15 | 16 | - name: install clang 17 | run: | 18 | wget https://apt.llvm.org/llvm.sh 19 | chmod +x llvm.sh 20 | sudo ./llvm.sh 20 21 | sudo apt install libc++-20-dev 22 | 23 | - name: check compiler version 24 | run: | 25 | clang++-20 --version 26 | 27 | - name: build and run test with clang 20 28 | run: | 29 | cmake -B build -GNinja -DCMAKE_C_COMPILER=clang-20 -DCMAKE_CXX_COMPILER=clang++-20 -DCMAKE_CXX_FLAGS="-stdlib=libc++" -DCMAKE_CXX_STANDARD=23 -DCMAKE_BUILD_TYPE=Release -DPROXY_BUILD_MODULES=TRUE 30 | cmake --build build -j 31 | ctest --test-dir build -j 32 | mkdir build/drop 33 | chmod +x tools/dump_build_env.sh 34 | ./tools/dump_build_env.sh clang++-20 build/drop/env-info.json 35 | 36 | - name: run benchmarks 37 | run: | 38 | build/benchmarks/msft_proxy_benchmarks --benchmark_min_warmup_time=0.1 --benchmark_min_time=0.1s --benchmark_repetitions=30 --benchmark_enable_random_interleaving=true --benchmark_report_aggregates_only=true --benchmark_format=json > build/drop/benchmarking-results.json 39 | 40 | - name: archive benchmarking results 41 | uses: actions/upload-artifact@v4 42 | with: 43 | name: drop-clang 44 | path: build/drop/ 45 | -------------------------------------------------------------------------------- /.github/workflows/bvt-compatibility.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | branch: 5 | type: string 6 | required: false 7 | 8 | jobs: 9 | bvt-compatibility: 10 | runs-on: ubuntu-24.04 11 | steps: 12 | - uses: actions/checkout@v4 13 | with: 14 | ref: ${{ inputs.branch }} 15 | 16 | - name: install compilers 17 | run: | 18 | sudo apt install -y gcc-13 g++-13 gcc-14 g++-14 clang-16 clang-17 clang-18 clang-19 libc++-19-dev 19 | 20 | - name: check compiler versions 21 | run: | 22 | g++-13 --version 23 | g++-14 --version 24 | clang++-16 --version 25 | clang++-17 --version 26 | clang++-18 --version 27 | clang++-19 --version 28 | 29 | - name: build and run test with gcc 14 30 | run: | 31 | cmake -B build-gcc-14 -GNinja -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_BUILD_TYPE=Release -DPROXY_BUILD_MODULES=TRUE 32 | cmake --build build-gcc-14 -j 33 | ctest --test-dir build-gcc-14 -j 34 | 35 | - name: build and run test with gcc 13 36 | run: | 37 | cmake -B build-gcc-13 -DCMAKE_C_COMPILER=gcc-13 -DCMAKE_CXX_COMPILER=g++-13 -DCMAKE_BUILD_TYPE=Release -DPROXY_BUILD_MODULES=FALSE 38 | cmake --build build-gcc-13 -j 39 | ctest --test-dir build-gcc-13 -j 40 | 41 | - name: build and run test with clang 19 42 | run: | 43 | cmake -B build-clang-19 -DCMAKE_C_COMPILER=clang-19 -DCMAKE_CXX_COMPILER=clang++-19 -DCMAKE_CXX_FLAGS="-stdlib=libc++" -DCMAKE_BUILD_TYPE=Release -DPROXY_BUILD_MODULES=FALSE 44 | cmake --build build-clang-19 -j 45 | ctest --test-dir build-clang-19 -j 46 | 47 | - name: build and run test with clang 18 48 | run: | 49 | cmake -B build-clang-18 -DCMAKE_C_COMPILER=clang-18 -DCMAKE_CXX_COMPILER=clang++-18 -DCMAKE_CXX_FLAGS="-stdlib=libc++" -DCMAKE_BUILD_TYPE=Release -DPROXY_BUILD_MODULES=FALSE 50 | cmake --build build-clang-18 -j 51 | ctest --test-dir build-clang-18 -j 52 | 53 | - name: build and run test with clang 17 54 | run: | 55 | cmake -B build-clang-17 -DCMAKE_C_COMPILER=clang-17 -DCMAKE_CXX_COMPILER=clang++-17 -DCMAKE_CXX_FLAGS="-stdlib=libc++" -DCMAKE_BUILD_TYPE=Release -DPROXY_BUILD_MODULES=FALSE 56 | cmake --build build-clang-17 -j 57 | ctest --test-dir build-clang-17 -j 58 | 59 | # Note that libc++ in Clang 19 is not compatible with Clang 16. Therefore, we fallback to libstdc++. 60 | - name: build and run test with clang 16 61 | run: | 62 | cmake -B build-clang-16 -DCMAKE_C_COMPILER=clang-16 -DCMAKE_CXX_COMPILER=clang++-16 -DCMAKE_BUILD_TYPE=Release -DPROXY_BUILD_MODULES=FALSE 63 | cmake --build build-clang-16 -j 64 | ctest --test-dir build-clang-16 -j 65 | -------------------------------------------------------------------------------- /.github/workflows/bvt-gcc.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | branch: 5 | type: string 6 | required: false 7 | 8 | jobs: 9 | bvt-gcc: 10 | runs-on: ubuntu-24.04 11 | steps: 12 | - uses: actions/checkout@v4 13 | with: 14 | ref: ${{ inputs.branch }} 15 | 16 | - name: install gcc 17 | run: | 18 | sudo apt install -y gcc-14 g++-14 19 | 20 | - name: check compiler version 21 | run: | 22 | g++-14 --version 23 | 24 | - name: build and run test with gcc 14 25 | run: | 26 | cmake -B build -GNinja -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_CXX_STANDARD=23 -DCMAKE_BUILD_TYPE=Release -DPROXY_BUILD_MODULES=TRUE 27 | cmake --build build -j 28 | ctest --test-dir build -j 29 | mkdir build/drop 30 | chmod +x tools/dump_build_env.sh 31 | ./tools/dump_build_env.sh g++-14 build/drop/env-info.json 32 | 33 | - name: run benchmarks 34 | run: | 35 | build/benchmarks/msft_proxy_benchmarks --benchmark_min_warmup_time=0.1 --benchmark_min_time=0.1s --benchmark_repetitions=30 --benchmark_enable_random_interleaving=true --benchmark_report_aggregates_only=true --benchmark_format=json > build/drop/benchmarking-results.json 36 | 37 | - name: archive benchmarking results 38 | uses: actions/upload-artifact@v4 39 | with: 40 | name: drop-gcc 41 | path: build/drop/ 42 | -------------------------------------------------------------------------------- /.github/workflows/bvt-msvc.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | branch: 5 | type: string 6 | required: false 7 | 8 | jobs: 9 | bvt-msvc: 10 | runs-on: windows-2025 11 | steps: 12 | - uses: actions/checkout@v4 13 | with: 14 | ref: ${{ inputs.branch }} 15 | 16 | - name: add cl.exe to PATH 17 | uses: ilammy/msvc-dev-cmd@v1 18 | 19 | - name: build and run test with MSVC 20 | run: | 21 | cmake -B build -DCMAKE_CXX_STANDARD=23 -DPROXY_BUILD_MODULES=TRUE 22 | cmake --build build --config Release -j 23 | ctest --test-dir build -j 24 | mkdir build\drop > $null 25 | .\tools\dump_build_env_msvc.ps1 -OutputPath build\drop\env-info.json 26 | 27 | - name: run benchmarks 28 | run: | 29 | build\benchmarks\Release\msft_proxy_benchmarks.exe --benchmark_min_warmup_time=0.1 --benchmark_min_time=0.1s --benchmark_repetitions=30 --benchmark_enable_random_interleaving=true --benchmark_report_aggregates_only=true --benchmark_format=json > build\drop\benchmarking-results.json 30 | 31 | - name: archive benchmarking results 32 | uses: actions/upload-artifact@v4 33 | with: 34 | name: drop-msvc 35 | path: build/drop/ 36 | -------------------------------------------------------------------------------- /.github/workflows/bvt-nvhpc.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | branch: 5 | type: string 6 | required: false 7 | 8 | jobs: 9 | bvt-nvhpc: 10 | runs-on: ubuntu-24.04 11 | steps: 12 | - uses: actions/checkout@v4 13 | with: 14 | ref: ${{ inputs.branch }} 15 | 16 | - name: install NVHPC 24.9 17 | run: | 18 | curl https://developer.download.nvidia.com/hpc-sdk/ubuntu/DEB-GPG-KEY-NVIDIA-HPC-SDK | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-hpcsdk-archive-keyring.gpg 19 | echo 'deb [signed-by=/usr/share/keyrings/nvidia-hpcsdk-archive-keyring.gpg] https://developer.download.nvidia.com/hpc-sdk/ubuntu/amd64 /' | sudo tee /etc/apt/sources.list.d/nvhpc.list 20 | sudo apt-get update -y 21 | sudo apt-get install -y nvhpc-24-9 22 | 23 | - name: build and run test with NVHPC 24.9 24 | run: | 25 | PATH=/opt/nvidia/hpc_sdk/Linux_x86_64/24.9/compilers/bin:$PATH; export PATH 26 | cmake -B build -GNinja -DCMAKE_C_COMPILER=nvc -DCMAKE_CXX_COMPILER=nvc++ -DCMAKE_BUILD_TYPE=Release -DPROXY_BUILD_MODULES=FALSE 27 | cmake --build build -j 28 | ctest --test-dir build -j 29 | mkdir build/drop 30 | chmod +x tools/dump_build_env.sh 31 | ./tools/dump_build_env.sh nvc++ build/drop/env-info.json 32 | 33 | - name: run benchmarks 34 | run: | 35 | build/benchmarks/msft_proxy_benchmarks --benchmark_min_warmup_time=0.1 --benchmark_min_time=0.1s --benchmark_repetitions=30 --benchmark_enable_random_interleaving=true --benchmark_report_aggregates_only=true --benchmark_format=json > build/drop/benchmarking-results.json 36 | 37 | - name: archive benchmarking results 38 | uses: actions/upload-artifact@v4 39 | with: 40 | name: drop-nvhpc 41 | path: build/drop/ 42 | -------------------------------------------------------------------------------- /.github/workflows/bvt-report.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | branch: 5 | type: string 6 | required: false 7 | 8 | jobs: 9 | bvt-report: 10 | runs-on: ubuntu-24.04 11 | steps: 12 | - uses: actions/checkout@v4 13 | with: 14 | ref: ${{ inputs.branch }} 15 | 16 | - name: download all workflow run artifacts 17 | uses: actions/download-artifact@v4 18 | with: 19 | path: artifacts 20 | 21 | - name: build report generator 22 | run: | 23 | cd tools/report_generator 24 | cmake -B build -DCMAKE_BUILD_TYPE=Release 25 | cmake --build build -j 26 | 27 | - name: generate report 28 | run: | 29 | cat < benchmarking-report.md 30 | # Benchmarking Report 31 | 32 | - Generated for: [Microsoft "Proxy" library](https://github.com/microsoft/proxy) 33 | - Commit ID: [${{ github.sha }}](https://github.com/microsoft/proxy/commit/${{ github.sha }}) 34 | - Generated at: $(date -u +"%Y-%m-%dT%H:%M:%SZ") 35 | 36 | EOF 37 | tools/report_generator/build/report_generator tools/report_generator/report-config.json 38 | 39 | - name: archive benchmarking report 40 | uses: actions/upload-artifact@v4 41 | with: 42 | name: benchmarking-report 43 | path: benchmarking-report.md 44 | -------------------------------------------------------------------------------- /.github/workflows/pipeline-ci.yml: -------------------------------------------------------------------------------- 1 | name: Proxy-CI 2 | 3 | on: 4 | push: 5 | branches: [ main, release/** ] 6 | pull_request: 7 | branches: [ main, release/** ] 8 | workflow_dispatch: 9 | 10 | jobs: 11 | run-bvt-gcc: 12 | uses: ./.github/workflows/bvt-gcc.yml 13 | name: Run BVT with GCC 14 | 15 | run-bvt-clang: 16 | uses: ./.github/workflows/bvt-clang.yml 17 | name: Run BVT with Clang 18 | 19 | run-bvt-msvc: 20 | uses: ./.github/workflows/bvt-msvc.yml 21 | name: Run BVT with MSVC 22 | 23 | run-bvt-appleclang: 24 | uses: ./.github/workflows/bvt-appleclang.yml 25 | name: Run BVT with AppleClang 26 | 27 | run-bvt-nvhpc: 28 | uses: ./.github/workflows/bvt-nvhpc.yml 29 | name: Run BVT with NVHPC 30 | 31 | run-bvt-compatibility: 32 | uses: ./.github/workflows/bvt-compatibility.yml 33 | name: Run BVT for compatibility 34 | 35 | report: 36 | uses: ./.github/workflows/bvt-report.yml 37 | name: Generate report 38 | needs: [run-bvt-gcc, run-bvt-clang, run-bvt-msvc, run-bvt-appleclang, run-bvt-nvhpc] 39 | -------------------------------------------------------------------------------- /.github/workflows/pipeline-release.yml: -------------------------------------------------------------------------------- 1 | name: Proxy-Release 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | draft-release: 8 | name: Draft release 9 | permissions: 10 | contents: write 11 | runs-on: ubuntu-24.04 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: pack source 15 | id: run-pack 16 | run: | 17 | version=$(grep -oP 'msft_proxy\s+VERSION\s+\K[0-9]+\.[0-9]+\.[0-9]+' CMakeLists.txt) 18 | git tag "$version" 19 | git push origin "$version" 20 | tar -czf "proxy-$version.tgz" proxy.h proxy_fmt.h 21 | echo "PRO_VER=$version" >> $GITHUB_OUTPUT 22 | shell: bash 23 | 24 | - name: create release draft 25 | uses: softprops/action-gh-release@v2 26 | with: 27 | draft: true 28 | tag_name: ${{ steps.run-pack.outputs.PRO_VER }} 29 | files: proxy-*.tgz 30 | name: Proxy ${{ steps.run-pack.outputs.PRO_VER }} Release 31 | generate_release_notes: true 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore build directories 2 | build/ 3 | Testing/ 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.28) 2 | 3 | project(msft_proxy VERSION 3.3.0 LANGUAGES CXX) 4 | add_library(msft_proxy INTERFACE) 5 | 6 | # Do not enable building tests if proxy is consumed as 7 | # subdirectory (e.g. by CMake FetchContent_Declare). 8 | if(PROJECT_IS_TOP_LEVEL) 9 | option(BUILD_TESTING "Build tests" ON) 10 | else() 11 | option(BUILD_TESTING "Build tests" OFF) 12 | endif() 13 | 14 | if(PROJECT_IS_TOP_LEVEL) 15 | option( 16 | PROXY_BUILD_MODULES 17 | "When this project is top level, build the docs and tests with C++ module support." 18 | OFF 19 | ) 20 | endif() 21 | 22 | target_sources(msft_proxy 23 | INTERFACE 24 | FILE_SET public_headers 25 | TYPE HEADERS 26 | BASE_DIRS include 27 | FILES 28 | include/proxy/proxy.h 29 | include/proxy/proxy_macros.h 30 | include/proxy/proxy_fmt.h 31 | include/proxy/proxy.ixx 32 | ) 33 | 34 | target_compile_features(msft_proxy INTERFACE cxx_std_20) 35 | target_include_directories(msft_proxy INTERFACE $ 36 | $) 37 | 38 | # Do not set the module target if proxy is consumed as a subdirectory. 39 | if(PROJECT_IS_TOP_LEVEL) 40 | set(proxy_INCLUDE_DIR include) 41 | if(PROXY_BUILD_MODULES) 42 | include(cmake/proxyModuleTargets.cmake) 43 | endif() 44 | else() 45 | # Propagate the variable to the parent project 46 | set(proxy_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE) 47 | endif() 48 | 49 | # install and export the project. project name - proxy 50 | 51 | include(GNUInstallDirs) 52 | 53 | install(TARGETS msft_proxy 54 | EXPORT proxyTargets 55 | FILE_SET public_headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 56 | ) 57 | 58 | install(EXPORT proxyTargets DESTINATION ${CMAKE_INSTALL_DATADIR}/proxy) 59 | export(TARGETS msft_proxy FILE proxyTargets.cmake) 60 | 61 | include(CMakePackageConfigHelpers) 62 | configure_package_config_file( 63 | cmake/proxyConfig.cmake.in 64 | ${CMAKE_CURRENT_BINARY_DIR}/cmake/proxyConfig.cmake 65 | INSTALL_DESTINATION ${CMAKE_INSTALL_DATADIR}/proxy 66 | PATH_VARS CMAKE_INSTALL_INCLUDEDIR 67 | ) 68 | 69 | include(CMakePackageConfigHelpers) 70 | write_basic_package_version_file(cmake/proxyConfigVersion.cmake 71 | COMPATIBILITY SameMajorVersion 72 | ARCH_INDEPENDENT) 73 | 74 | install( 75 | FILES 76 | ${CMAKE_CURRENT_BINARY_DIR}/cmake/proxyConfig.cmake 77 | ${CMAKE_CURRENT_BINARY_DIR}/cmake/proxyConfigVersion.cmake 78 | DESTINATION ${CMAKE_INSTALL_DATADIR}/proxy 79 | ) 80 | 81 | # build tests if BUILD_TESTING is ON 82 | if (BUILD_TESTING) 83 | include(CTest) 84 | add_subdirectory(tests) 85 | add_subdirectory(benchmarks) 86 | add_subdirectory(docs) 87 | endif() 88 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # TODO: The maintainer of this repo has not yet edited this file 2 | 3 | **REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project? 4 | 5 | - **No CSS support:** Fill out this template with information about how to file issues and get help. 6 | - **Yes CSS support:** Fill out an intake form at [aka.ms/onboardsupport](https://aka.ms/onboardsupport). CSS will work with/help you to determine next steps. 7 | - **Not sure?** Fill out an intake as though the answer were "Yes". CSS will help you decide. 8 | 9 | *Then remove this first heading from this SUPPORT.MD file before publishing your repo.* 10 | 11 | # Support 12 | 13 | ## How to file issues and get help 14 | 15 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing 16 | issues before filing new issues to avoid duplicates. For new issues, file your bug or 17 | feature request as a new Issue. 18 | 19 | For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE 20 | FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER 21 | CHANNEL. WHERE WILL YOU HELP PEOPLE?**. 22 | 23 | ## Microsoft Support Policy 24 | 25 | Support for this **PROJECT or PRODUCT** is limited to the resources listed above. 26 | -------------------------------------------------------------------------------- /benchmarks/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(msft_proxy_benchmarks) 2 | 3 | include(FetchContent) 4 | # The policy uses the download time for timestamp, instead of the timestamp in the archive. This 5 | # allows for proper rebuilds when a projects URL changes. 6 | if(POLICY CMP0135) 7 | cmake_policy(SET CMP0135 NEW) 8 | endif() 9 | 10 | FetchContent_Declare( 11 | benchmark 12 | URL https://github.com/google/benchmark/archive/refs/tags/v1.9.0.tar.gz 13 | URL_HASH SHA256=35a77f46cc782b16fac8d3b107fbfbb37dcd645f7c28eee19f3b8e0758b48994 14 | ) 15 | set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Disable tests for google benchmark") 16 | set(BENCHMARK_ENABLE_GTEST_TESTS OFF CACHE BOOL "Disable google benchmark unit tests") 17 | FetchContent_MakeAvailable(benchmark) 18 | 19 | add_executable(msft_proxy_benchmarks 20 | proxy_invocation_benchmark_context.cpp 21 | proxy_invocation_benchmark.cpp 22 | proxy_management_benchmark.cpp 23 | ) 24 | target_include_directories(msft_proxy_benchmarks PRIVATE .) 25 | target_link_libraries(msft_proxy_benchmarks PRIVATE msft_proxy benchmark::benchmark benchmark::benchmark_main) 26 | 27 | if (MSVC) 28 | target_compile_options(msft_proxy_benchmarks PRIVATE /W4) 29 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 30 | target_compile_options(msft_proxy_benchmarks PRIVATE -Wall -Wextra -Wpedantic -Wno-c++2b-extensions) 31 | else() 32 | target_compile_options(msft_proxy_benchmarks PRIVATE -Wall -Wextra -Wpedantic) 33 | endif() 34 | -------------------------------------------------------------------------------- /benchmarks/proxy_invocation_benchmark.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #include 5 | 6 | #include "proxy_invocation_benchmark_context.h" 7 | 8 | namespace { 9 | 10 | void BM_SmallObjectInvocationViaProxy(benchmark::State& state) { 11 | auto data = GenerateSmallObjectInvocationProxyTestData(); 12 | std::vector> views(data.begin(), data.end()); 13 | for (auto _ : state) { 14 | for (auto& p : views) { 15 | int result = p->Fun(); 16 | benchmark::DoNotOptimize(result); 17 | } 18 | } 19 | } 20 | 21 | void BM_SmallObjectInvocationViaProxy_Shared(benchmark::State& state) { 22 | auto data = GenerateSmallObjectInvocationProxyTestData_Shared(); 23 | std::vector> views(data.begin(), data.end()); 24 | for (auto _ : state) { 25 | for (auto& p : views) { 26 | int result = p->Fun(); 27 | benchmark::DoNotOptimize(result); 28 | } 29 | } 30 | } 31 | 32 | void BM_SmallObjectInvocationViaProxyView(benchmark::State& state) { 33 | auto data = GenerateSmallObjectInvocationProxyTestData(); 34 | for (auto _ : state) { 35 | for (auto& p : data) { 36 | int result = p->Fun(); 37 | benchmark::DoNotOptimize(result); 38 | } 39 | } 40 | } 41 | 42 | void BM_SmallObjectInvocationViaVirtualFunction(benchmark::State& state) { 43 | auto data = GenerateSmallObjectInvocationVirtualFunctionTestData(); 44 | for (auto _ : state) { 45 | for (auto& p : data) { 46 | int result = p->Fun(); 47 | benchmark::DoNotOptimize(result); 48 | } 49 | } 50 | } 51 | 52 | void BM_SmallObjectInvocationViaVirtualFunction_Shared(benchmark::State& state) { 53 | auto data = GenerateSmallObjectInvocationVirtualFunctionTestData_Shared(); 54 | for (auto _ : state) { 55 | for (auto& p : data) { 56 | int result = p->Fun(); 57 | benchmark::DoNotOptimize(result); 58 | } 59 | } 60 | } 61 | 62 | void BM_LargeObjectInvocationViaProxy(benchmark::State& state) { 63 | auto data = GenerateLargeObjectInvocationProxyTestData(); 64 | for (auto _ : state) { 65 | for (auto& p : data) { 66 | int result = p->Fun(); 67 | benchmark::DoNotOptimize(result); 68 | } 69 | } 70 | } 71 | 72 | void BM_LargeObjectInvocationViaProxy_Shared(benchmark::State& state) { 73 | auto data = GenerateLargeObjectInvocationProxyTestData_Shared(); 74 | for (auto _ : state) { 75 | for (auto& p : data) { 76 | int result = p->Fun(); 77 | benchmark::DoNotOptimize(result); 78 | } 79 | } 80 | } 81 | 82 | void BM_LargeObjectInvocationViaProxyView(benchmark::State& state) { 83 | auto data = GenerateLargeObjectInvocationProxyTestData(); 84 | std::vector> views(data.begin(), data.end()); 85 | for (auto _ : state) { 86 | for (auto& p : views) { 87 | int result = p->Fun(); 88 | benchmark::DoNotOptimize(result); 89 | } 90 | } 91 | } 92 | 93 | void BM_LargeObjectInvocationViaVirtualFunction(benchmark::State& state) { 94 | auto data = GenerateLargeObjectInvocationVirtualFunctionTestData(); 95 | for (auto _ : state) { 96 | for (auto& p : data) { 97 | int result = p->Fun(); 98 | benchmark::DoNotOptimize(result); 99 | } 100 | } 101 | } 102 | 103 | void BM_LargeObjectInvocationViaVirtualFunction_Shared(benchmark::State& state) { 104 | auto data = GenerateLargeObjectInvocationVirtualFunctionTestData(); 105 | for (auto _ : state) { 106 | for (auto& p : data) { 107 | int result = p->Fun(); 108 | benchmark::DoNotOptimize(result); 109 | } 110 | } 111 | } 112 | 113 | BENCHMARK(BM_SmallObjectInvocationViaProxy); 114 | BENCHMARK(BM_SmallObjectInvocationViaProxy_Shared); 115 | BENCHMARK(BM_SmallObjectInvocationViaProxyView); 116 | BENCHMARK(BM_SmallObjectInvocationViaVirtualFunction); 117 | BENCHMARK(BM_SmallObjectInvocationViaVirtualFunction_Shared); 118 | BENCHMARK(BM_LargeObjectInvocationViaProxy); 119 | BENCHMARK(BM_LargeObjectInvocationViaProxy_Shared); 120 | BENCHMARK(BM_LargeObjectInvocationViaProxyView); 121 | BENCHMARK(BM_LargeObjectInvocationViaVirtualFunction); 122 | BENCHMARK(BM_LargeObjectInvocationViaVirtualFunction_Shared); 123 | 124 | } // namespace 125 | -------------------------------------------------------------------------------- /benchmarks/proxy_invocation_benchmark_context.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #include "proxy_invocation_benchmark_context.h" 5 | 6 | namespace { 7 | 8 | constexpr int TestDataSize = 1000000; 9 | constexpr int TypeSeriesCount = 100; 10 | 11 | template 12 | class NonIntrusiveSmallImpl { 13 | public: 14 | explicit NonIntrusiveSmallImpl(int seed) noexcept : seed_(seed) {} 15 | NonIntrusiveSmallImpl(const NonIntrusiveSmallImpl&) noexcept = default; 16 | int Fun() const noexcept { return seed_ ^ (TypeSeries + 1); } 17 | 18 | private: 19 | int seed_; 20 | }; 21 | 22 | template 23 | class NonIntrusiveLargeImpl { 24 | public: 25 | explicit NonIntrusiveLargeImpl(int seed) noexcept : seed_(seed) {} 26 | NonIntrusiveLargeImpl(const NonIntrusiveLargeImpl&) noexcept = default; 27 | int Fun() const noexcept { return seed_ ^ (TypeSeries + 1); } 28 | 29 | private: 30 | void* padding_[5]{}; 31 | int seed_; 32 | }; 33 | 34 | template 35 | class IntrusiveSmallImpl : public InvocationTestBase { 36 | public: 37 | explicit IntrusiveSmallImpl(int seed) noexcept : seed_(seed) {} 38 | IntrusiveSmallImpl(const IntrusiveSmallImpl&) noexcept = default; 39 | int Fun() const noexcept override { return seed_ ^ (TypeSeries + 1); } 40 | 41 | private: 42 | int seed_; 43 | }; 44 | 45 | template 46 | class IntrusiveLargeImpl : public InvocationTestBase { 47 | public: 48 | explicit IntrusiveLargeImpl(int seed) noexcept : seed_(seed) {} 49 | IntrusiveLargeImpl(const IntrusiveLargeImpl&) noexcept = default; 50 | int Fun() const noexcept override { return seed_ ^ (TypeSeries + 1); } 51 | 52 | private: 53 | void* padding_[5]{}; 54 | int seed_; 55 | }; 56 | 57 | template 58 | struct IntConstant {}; 59 | 60 | template 61 | void FillTestData(std::vector& data, const F& generator) { 62 | if constexpr (FromTypeSeries < TypeSeriesCount) { 63 | for (int i = FromTypeSeries; i < TestDataSize; i += TypeSeriesCount) { 64 | data[i] = generator(IntConstant{}, i); 65 | } 66 | FillTestData(data, generator); 67 | } 68 | } 69 | 70 | template 71 | auto GenerateTestData(const F& generator) { 72 | std::vector{}, 0))> result(TestDataSize); 73 | FillTestData<0>(result, generator); 74 | return result; 75 | } 76 | 77 | } // namespace 78 | 79 | std::vector> GenerateSmallObjectInvocationProxyTestData() { 80 | return GenerateTestData([](IntConstant, int seed) 81 | { return pro::make_proxy>(seed); }); 82 | } 83 | std::vector> GenerateSmallObjectInvocationProxyTestData_Shared() { 84 | return GenerateTestData([](IntConstant, int seed) 85 | { return pro::make_proxy_shared>(seed); }); 86 | } 87 | std::vector> GenerateSmallObjectInvocationVirtualFunctionTestData() { 88 | return GenerateTestData([](IntConstant, int seed) 89 | { return std::unique_ptr{new IntrusiveSmallImpl(seed)}; }); 90 | } 91 | std::vector> GenerateSmallObjectInvocationVirtualFunctionTestData_Shared() { 92 | return GenerateTestData([](IntConstant, int seed) 93 | { return std::shared_ptr{std::make_shared>(seed)}; }); 94 | } 95 | std::vector> GenerateLargeObjectInvocationProxyTestData() { 96 | return GenerateTestData([](IntConstant, int seed) 97 | { return pro::make_proxy>(seed); }); 98 | } 99 | std::vector> GenerateLargeObjectInvocationProxyTestData_Shared() { 100 | return GenerateTestData([](IntConstant, int seed) 101 | { return pro::make_proxy_shared>(seed); }); 102 | } 103 | std::vector> GenerateLargeObjectInvocationVirtualFunctionTestData() { 104 | return GenerateTestData([](IntConstant, int seed) 105 | { return std::unique_ptr{new IntrusiveLargeImpl(seed)}; }); 106 | } 107 | std::vector> GenerateLargeObjectInvocationVirtualFunctionTestData_Shared() { 108 | return GenerateTestData([](IntConstant, int seed) 109 | { return std::shared_ptr{std::make_shared>(seed)}; }); 110 | } 111 | -------------------------------------------------------------------------------- /benchmarks/proxy_invocation_benchmark_context.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | PRO_DEF_MEM_DISPATCH(MemFun, Fun); 10 | 11 | struct InvocationTestFacade : pro::facade_builder 12 | ::add_convention 13 | ::support 14 | ::build{}; 15 | 16 | struct InvocationTestBase { 17 | virtual int Fun() const = 0; 18 | virtual ~InvocationTestBase() = default; 19 | }; 20 | 21 | std::vector> GenerateSmallObjectInvocationProxyTestData(); 22 | std::vector> GenerateSmallObjectInvocationProxyTestData_Shared(); 23 | std::vector> GenerateSmallObjectInvocationVirtualFunctionTestData(); 24 | std::vector> GenerateSmallObjectInvocationVirtualFunctionTestData_Shared(); 25 | std::vector> GenerateLargeObjectInvocationProxyTestData(); 26 | std::vector> GenerateLargeObjectInvocationProxyTestData_Shared(); 27 | std::vector> GenerateLargeObjectInvocationVirtualFunctionTestData(); 28 | std::vector> GenerateLargeObjectInvocationVirtualFunctionTestData_Shared(); 29 | -------------------------------------------------------------------------------- /cmake/proxyConfig.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include("${CMAKE_CURRENT_LIST_DIR}/proxyTargets.cmake") 4 | 5 | set(proxy_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@") 6 | -------------------------------------------------------------------------------- /cmake/proxyModuleTargets.cmake: -------------------------------------------------------------------------------- 1 | 2 | if(NOT DEFINED proxy_INCLUDE_DIR) 3 | message(FATAL_ERROR "proxy_INCLUDE_DIR must be defined to use this script.") 4 | endif() 5 | 6 | message(STATUS "Declaring `msft_proxy::module` target for include path ${proxy_INCLUDE_DIR}") 7 | 8 | add_library(msft_proxy_module) 9 | set_target_properties( 10 | msft_proxy_module 11 | PROPERTIES 12 | SYSTEM TRUE 13 | EXCLUDE_FROM_ALL TRUE 14 | ) 15 | 16 | add_library(msft_proxy::module ALIAS msft_proxy_module) 17 | target_sources(msft_proxy_module PUBLIC 18 | FILE_SET CXX_MODULES 19 | BASE_DIRS ${proxy_INCLUDE_DIR} 20 | FILES 21 | ${proxy_INCLUDE_DIR}/proxy/proxy.ixx 22 | ) 23 | target_compile_features(msft_proxy_module PUBLIC cxx_std_20) 24 | target_link_libraries(msft_proxy_module PUBLIC msft_proxy) 25 | 26 | -------------------------------------------------------------------------------- /docs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(msft_proxy_docs) 2 | 3 | find_package(Python3 REQUIRED COMPONENTS Interpreter) 4 | 5 | file(GLOB_RECURSE DOC_FILES "*.md") 6 | set(EXTRACTION_SCRIPT ${CMAKE_SOURCE_DIR}/tools/extract_example_code_from_docs.py) 7 | set(EXAMPLES_DIR ${CMAKE_BINARY_DIR}/examples_from_docs) 8 | file(MAKE_DIRECTORY "${EXAMPLES_DIR}") 9 | execute_process( 10 | COMMAND ${Python3_EXECUTABLE} ${EXTRACTION_SCRIPT} ${CMAKE_CURRENT_SOURCE_DIR} ${EXAMPLES_DIR} 11 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 12 | COMMAND_ERROR_IS_FATAL ANY 13 | ) 14 | 15 | file(GLOB EXAMPLE_SOURCES "${EXAMPLES_DIR}/*.cpp") 16 | set_source_files_properties(${EXAMPLE_SOURCES} PROPERTIES GENERATED TRUE) 17 | foreach(SOURCE ${EXAMPLE_SOURCES}) 18 | get_filename_component(EXECUTABLE_NAME ${SOURCE} NAME_WE) 19 | add_executable(${EXECUTABLE_NAME} ${SOURCE}) 20 | target_link_libraries(${EXECUTABLE_NAME} PRIVATE msft_proxy) 21 | if (MSVC) 22 | target_compile_options(${EXECUTABLE_NAME} PRIVATE /W4) 23 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 24 | target_compile_options(${EXECUTABLE_NAME} PRIVATE -Wall -Wextra -Wpedantic -Wno-c++2b-extensions) 25 | else() 26 | target_compile_options(${EXECUTABLE_NAME} PRIVATE -Wall -Wextra -Wpedantic) 27 | endif() 28 | endforeach() 29 | -------------------------------------------------------------------------------- /docs/PRO_DEF_FREE_AS_MEM_DISPATCH.md: -------------------------------------------------------------------------------- 1 | # Macro `PRO_DEF_FREE_AS_MEM_DISPATCH` 2 | 3 | ```cpp 4 | #define PRO_DEF_FREE_AS_MEM_DISPATCH // since 3.1.0, see below 5 | ``` 6 | 7 | Macro `PRO_DEF_FREE_AS_MEM_DISPATCH` defines dispatch types for free function expressions with accessibility via a member function. It supports two syntaxes: 8 | 9 | ```cpp 10 | // (1) 11 | PRO_DEF_FREE_AS_MEM_DISPATCH(dispatch_name, func_name); 12 | 13 | // (2) 14 | PRO_DEF_FREE_AS_MEM_DISPATCH(dispatch_name, func_name, accessibility_func_name); 15 | ``` 16 | 17 | `(1)` Equivalent to `PRO_DEF_FREE_AS_MEM_DISPATCH(dispatch_name, func_name, func_name);` 18 | 19 | `(2)` Defines a class named `dispatch_name` of free function call expressions of `func_name` with accessibility via member function overloads named `accessibility_func_name`. Effectively equivalent to: 20 | 21 | ```cpp 22 | struct dispatch_name { 23 | template 24 | decltype(auto) operator()(T&& self, Args&&... args) const 25 | noexcept(noexcept(func_name(std::forward(self), std::forward(args)...))) 26 | requires(requires { func_name(std::forward(self), std::forward(args)...); }) { 27 | return func_name(std::forward(self), std::forward(args)...); 28 | } 29 | 30 | template 31 | struct accessor { 32 | accessor() = delete; 33 | }; 34 | template 35 | requires(sizeof...(Os) > 1u && (std::is_constructible_v> && ...)) 36 | struct accessor : accessor... { 37 | using accessor::accessibility_func_name ...; 38 | }; 39 | template 40 | struct accessor { 41 | R accessibility_func_name(Args... args) cv ref noex { 42 | return pro::proxy_invoke(pro::access_proxy(std::forward(*this)), std::forward(args)...); 43 | } 44 | }; 45 | } 46 | ``` 47 | 48 | ## Example 49 | 50 | ```cpp 51 | #include 52 | #include 53 | 54 | #include 55 | 56 | PRO_DEF_FREE_AS_MEM_DISPATCH(FreeToString, std::to_string, ToString); 57 | 58 | struct Stringable : pro::facade_builder 59 | ::add_convention 60 | ::build {}; 61 | 62 | int main() { 63 | pro::proxy p = pro::make_proxy(123); 64 | std::cout << p->ToString() << "\n"; // Prints "123" 65 | } 66 | ``` 67 | 68 | ## See Also 69 | 70 | - [macro `PRO_DEF_FREE_DISPATCH`](PRO_DEF_FREE_DISPATCH.md) 71 | - [alias template `basic_facade_builder::add_convention`](basic_facade_builder/add_convention.md) 72 | -------------------------------------------------------------------------------- /docs/PRO_DEF_FREE_DISPATCH.md: -------------------------------------------------------------------------------- 1 | # Macro `PRO_DEF_FREE_DISPATCH` 2 | 3 | ```cpp 4 | #define PRO_DEF_FREE_DISPATCH // see below 5 | ``` 6 | 7 | Macro `PRO_DEF_FREE_DISPATCH` defines dispatch types for free function expressions with accessibility. It supports two syntaxes: 8 | 9 | ```cpp 10 | // (1) 11 | PRO_DEF_FREE_DISPATCH(dispatch_name, func_name); 12 | 13 | // (2) 14 | PRO_DEF_FREE_DISPATCH(dispatch_name, func_name, accessibility_func_name); 15 | ``` 16 | 17 | `(1)` Equivalent to `PRO_DEF_FREE_DISPATCH(dispatch_name, func_name, func_name);` 18 | 19 | `(2)` Defines a class named `dispatch_name` of free function call expressions of `func_name` with accessibility via free function overloads named `accessibility_func_name`. Effectively equivalent to: 20 | 21 | ```cpp 22 | struct dispatch_name { 23 | template 24 | decltype(auto) operator()(T&& self, Args&&... args) const 25 | noexcept(noexcept(func_name(std::forward(self), std::forward(args)...))) 26 | requires(requires { func_name(std::forward(self), std::forward(args)...); }) { 27 | return func_name(std::forward(self), std::forward(args)...); 28 | } 29 | 30 | template 31 | struct accessor { 32 | accessor() = delete; 33 | }; 34 | template 35 | requires(sizeof...(Os) > 1u && (std::is_constructible_v> && ...)) 36 | struct accessor : accessor... {}; 37 | template 38 | struct accessor { 39 | friend R accessibility_func_name(accessor_arg cv ref self, Args... args) noex { 40 | return pro::proxy_invoke(pro::access_proxy(std::forward(self)), std::forward(args)...); 41 | } 42 | }; 43 | } 44 | ``` 45 | 46 | ## Example 47 | 48 | ```cpp 49 | #include 50 | #include 51 | 52 | #include 53 | 54 | PRO_DEF_FREE_DISPATCH(FreeToString, std::to_string, ToString); 55 | 56 | struct Stringable : pro::facade_builder 57 | ::add_convention 58 | ::build {}; 59 | 60 | int main() { 61 | pro::proxy p = pro::make_proxy(123); 62 | std::cout << ToString(*p) << "\n"; // Prints "123" 63 | } 64 | ``` 65 | 66 | ## See Also 67 | 68 | - [macro `PRO_DEF_MEM_DISPATCH`](PRO_DEF_MEM_DISPATCH.md) 69 | - [macro `PRO_DEF_FREE_AS_MEM_DISPATCH`](PRO_DEF_FREE_AS_MEM_DISPATCH.md) 70 | - [alias template `basic_facade_builder::add_convention`](basic_facade_builder/add_convention.md) 71 | -------------------------------------------------------------------------------- /docs/PRO_DEF_MEM_DISPATCH.md: -------------------------------------------------------------------------------- 1 | # Macro `PRO_DEF_MEM_DISPATCH` 2 | 3 | ```cpp 4 | #define PRO_DEF_MEM_DISPATCH // see below 5 | ``` 6 | 7 | Macro `PRO_DEF_MEM_DISPATCH` defines dispatch types for member function expressions with accessibility. It supports two syntaxes: 8 | 9 | ```cpp 10 | // (1) 11 | PRO_DEF_MEM_DISPATCH(dispatch_name, func_name); 12 | 13 | // (2) 14 | PRO_DEF_MEM_DISPATCH(dispatch_name, func_name, accessibility_func_name); 15 | ``` 16 | 17 | `(1)` Equivalent to `PRO_DEF_MEM_DISPATCH(dispatch_name, func_name, func_name);` 18 | 19 | `(2)` Defines a class named `dispatch_name` of member function call expressions of `func_name` with accessibility via member function overloads named `accessibility_func_name`. Effectively equivalent to: 20 | 21 | ```cpp 22 | struct dispatch_name { 23 | template 24 | decltype(auto) operator()(T&& self, Args&&... args) const 25 | noexcept(noexcept(std::forward(self).func_name(std::forward(args)...))) 26 | requires(requires { std::forward(self).func_name(std::forward(args)...); }) { 27 | return std::forward(self).func_name(std::forward(args)...); 28 | } 29 | 30 | template 31 | struct accessor { 32 | accessor() = delete; 33 | }; 34 | template 35 | requires(sizeof...(Os) > 1u && (std::is_constructible_v> && ...)) 36 | struct accessor : accessor... { 37 | using accessor::accessibility_func_name ...; 38 | }; 39 | template 40 | struct accessor { 41 | R accessibility_func_name(Args... args) cv ref noex { 42 | return pro::proxy_invoke(pro::access_proxy(std::forward(*this)), std::forward(args)...); 43 | } 44 | }; 45 | } 46 | ``` 47 | 48 | ## Example 49 | 50 | ```cpp 51 | #include 52 | #include 53 | #include 54 | 55 | #include 56 | 57 | PRO_DEF_MEM_DISPATCH(MemAt, at); 58 | 59 | struct Dictionary : pro::facade_builder 60 | ::add_convention 61 | ::build {}; 62 | 63 | int main() { 64 | std::vector v{"hello", "world"}; 65 | pro::proxy p = &v; 66 | std::cout << p->at(1) << "\n"; // Prints "world" 67 | } 68 | ``` 69 | 70 | ## See Also 71 | 72 | - [macro `PRO_DEF_FREE_DISPATCH`](PRO_DEF_FREE_DISPATCH.md) 73 | - [alias template `basic_facade_builder::add_convention`](basic_facade_builder/add_convention.md) 74 | -------------------------------------------------------------------------------- /docs/ProAccessible.md: -------------------------------------------------------------------------------- 1 | # Named requirements: *ProAccessible* 2 | 3 | Given that `F` is a type meeting the [*ProBasicFacade* requirements](ProBasicFacade.md), a type `T` meets the *ProAccessible* requirements of type `F`, if the following expressions are well-formed and have the specified semantics. 4 | 5 | | Expressions | Semantics | 6 | | ---------------------------------- | ------------------------------------------------------------ | 7 | | `typename T::template accessor` | A type that provides accessibility to `proxy`. It shall be a *nothrow-default-constructible*, *trivially-copyable* type, and shall not be [final](https://en.cppreference.com/w/cpp/language/final). | 8 | 9 | ## See Also 10 | 11 | - [class template `proxy`](proxy.md) 12 | -------------------------------------------------------------------------------- /docs/ProBasicConvention.md: -------------------------------------------------------------------------------- 1 | # Named requirements: *ProBasicConvention* 2 | 3 | A type `C` meets the *ProBasicConvention* requirements if the following expressions are well-formed and have the specified semantics. 4 | 5 | | Expressions | Semantics | 6 | | ---------------------------- | ------------------------------------------------------------ | 7 | | `C::is_direct` | A [core constant expression](https://en.cppreference.com/w/cpp/language/constant_expression) of type `bool`, specifying whether the convention applies to a pointer type itself (`true`), or the element type of a pointer type (`false`). | 8 | | `typename C::dispatch_type` | A [trivial type](https://en.cppreference.com/w/cpp/named_req/TrivialType) that defines how the calls are forwarded to the concrete types. | 9 | | `typename C::overload_types` | A [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type of one or more distinct types `Os`. Each type `O` in `Os` shall meet the [*ProOverload* requirements](ProOverload.md). | 10 | 11 | ## See Also 12 | 13 | - [*ProBasicFacade* requirements](ProBasicFacade.md) 14 | - [*ProConvention* requirements](ProConvention.md) 15 | -------------------------------------------------------------------------------- /docs/ProBasicFacade.md: -------------------------------------------------------------------------------- 1 | # Named requirements: *ProBasicFacade* 2 | 3 | A type `F` meets the *ProBasicFacade* requirements if the following expressions are well-formed and have the specified semantics. 4 | 5 | | Expressions | Semantics | 6 | | ------------------------------ | ------------------------------------------------------------ | 7 | | `typename F::convention_types` | A [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type that contains any number of distinct types `Cs`. Each type `C` in `Cs` shall meet the [*ProBasicConvention* requirements](ProBasicConvention.md). | 8 | | `typename F::reflection_types` | A [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type that contains any number of distinct types `Rs`. Each type `R` in `Rs` shall define reflection on pointer types. | 9 | | `F::constraints` | A [core constant expression](https://en.cppreference.com/w/cpp/language/constant_expression) of type [`proxiable_ptr_constraints`](proxiable_ptr_constraints.md) that defines constraints to pointer types. | 10 | 11 | ## See Also 12 | 13 | - [concept `facade`](facade.md) 14 | -------------------------------------------------------------------------------- /docs/ProBasicReflection.md: -------------------------------------------------------------------------------- 1 | # Named requirements: *ProBasicReflection* 2 | 3 | A type `R` meets the *ProBasicReflection* requirements if the following expressions are well-formed and have the specified semantics. 4 | 5 | | Expressions | Semantics | 6 | | ---------------------------- | ------------------------------------------------------------ | 7 | | `R::is_direct` | A [core constant expression](https://en.cppreference.com/w/cpp/language/constant_expression) of type `bool`, specifying whether the reflection applies to a pointer type itself (`true`), or the element type of a pointer type (`false`). | 8 | | `typename R::reflector_type` | A [trivial type](https://en.cppreference.com/w/cpp/named_req/TrivialType) that defines the data structure reflected from the type. | 9 | 10 | ## See Also 11 | 12 | - [*ProBasicFacade* requirements](ProBasicFacade.md) 13 | - [*ProReflection* requirements](ProReflection.md) 14 | -------------------------------------------------------------------------------- /docs/ProConvention.md: -------------------------------------------------------------------------------- 1 | # Named requirements: *ProConvention* 2 | 3 | A type `C` meets the *ProConvention* requirements of a type `P` if `C` meets the [*ProBasicConvention* requirements](ProBasicConvention.md), and the following expressions are well-formed and have the specified semantics. 4 | 5 | | Expressions | Semantics | 6 | | ---------------------------- | ------------------------------------------------------------ | 7 | | `typename C::overload_types` | A [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type that contains one or more distinct types `Os`. Each type `O` in `Os` shall meet the [*ProOverload* requirements](ProOverload.md), and
- when `C::is_direct` is `true`, `typename C::dispatch_type` shall meet the [*ProDispatch* requirements](ProDispatch.md) of `P` and `O`,
- or otherwise, when `C::is_direct` is `false`, let `QP` be a qualified reference type of `P` with the *cv ref* qualifiers defined by `O` (`QP` is an lvalue reference type if `O` does not define a *ref* qualifier), `qp` be a value of `QP`, `*std::forward(qp)` shall be well-formed, and `typename C::dispatch_type` shall meet the [*ProDispatch* requirements](ProDispatch.md) of `decltype(*std::forward(qp))` and `O`. | 8 | 9 | ## See Also 10 | 11 | - [*ProFacade* requirements](ProFacade.md) 12 | -------------------------------------------------------------------------------- /docs/ProDispatch.md: -------------------------------------------------------------------------------- 1 | # Named requirements: *ProDispatch* 2 | 3 | A type `D` meets the *ProDispatch* requirements of types `T` and `O` if `D` is a [trivial type](https://en.cppreference.com/w/cpp/named_req/TrivialType), `O` meets the [*ProOverload* requirelemts](ProOverload.md), and the following expressions are well-formed and have the specified semantics (let `R` be return type of `O`, `Args...` be the argument types of `O`. `args...` denotes values of type `Args...`, `v` denotes a value of type `T`, `cv` denotes a value of type `const T`). 4 | 5 | | Definitions of `O` | Expressions | Semantics | 6 | | ----------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | 7 | | `R(Args...)` | [`INVOKE`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, v, std::forward(args)...)` | Invokes dispatch type `D` with an lvalue reference of type `T` and `args...`, may throw. | 8 | | `R(Args...) noexcept` | [`INVOKE`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, v, std::forward(args)...)` | Invokes dispatch type `D` with an lvalue reference of type `T` and `args...`, shall not throw. | 9 | | `R(Args...) &` | [`INVOKE`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, v, std::forward(args)...)` | Invokes dispatch type `D` with an lvalue reference of type `T` and `args...`, may throw. | 10 | | `R(Args...) & noexcept` | [`INVOKE`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, v, std::forward(args)...)` | Invokes dispatch type `D` with an lvalue reference of type `T` and `args...`, shall not throw. | 11 | | `R(Args...) &&` | [`INVOKE`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, std::move(v), std::forward(args)...)` | Invokes dispatch type `D` with a rvalue reference of type `T` and `args...`, may throw. | 12 | | `R(Args...) && noexcept` | [`INVOKE`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, std::move(v), std::forward(args)...)` | Invokes dispatch type `D` with a rvalue reference of type `T` and `args...`, shall not throw. | 13 | | `R(Args...) const` | [`INVOKE`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, cv, std::forward(args)...)` | Invokes dispatch type `D` with a const reference of type `T` and `args...`, may throw. | 14 | | `R(Args...) const noexcept` | [`INVOKE`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, cv, std::forward(args)...)` | Invokes dispatch type `D` with a const reference of type `T` and `args...`, shall not throw. | 15 | | `R(Args...) cosnt&` | [`INVOKE`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, cv, std::forward(args)...)`, or
`d(nullptr, std::forward(args)...)` | Invokes dispatch type `D` with a const reference of type `T` and `args...`, may throw. | 16 | | `R(Args...) const& noexcept` | [`INVOKE`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, cv, std::forward(args)...)` | Invokes dispatch type `D` with a const reference of type `T` and `args...`, shall not throw. | 17 | | `R(Args...) const&&` | [`INVOKE`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, std::move(cv), std::forward(args)...)` | Invokes dispatch type `D` with a const rvalue reference of type `T` and `args...`, may throw. | 18 | | `R(Args...) const&& noexcept` | [`INVOKE`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, std::move(cv), std::forward(args)...)` | Invokes dispatch type `D` with a const rvalue reference of type `T` and `args...`, shall not throw. | 19 | 20 | Or, 21 | 22 | | Definitions of `O` | Expressions | Semantics | 23 | | -------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | 24 | | `R(Args...)` *cv ref noex* | [`INVOKE`](https://en.cppreference.com/w/cpp/utility/functional)`(D{}, nullptr, std::forward(args)...)` | Invokes the dispatch type `D` with `nullptr` and `args...`, may or may not throw depending on `noex`. | 25 | 26 | ## See Also 27 | 28 | - [*ProConvention* requirements](ProConvention.md) 29 | -------------------------------------------------------------------------------- /docs/ProFacade.md: -------------------------------------------------------------------------------- 1 | # Named requirements: *ProFacade* 2 | 3 | A type `F` meets the *ProFacade* requirements of a type `P` if `F` meets the [*ProBasicFacade* requirements](ProBasicFacade.md), and `P` meets the requirements defined by [`F::constraints`](proxiable_ptr_constraints.md), and the following expressions are well-formed and have the specified semantics. 4 | 5 | | Expressions | Semantics | 6 | | ------------------------------ | ------------------------------------------------------------ | 7 | | `typename F::convention_types` | A [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type that contains any number of distinct types `Cs`. Each type `C` in `Cs` shall meet the [*ProConvention* requirements](ProConvention.md) of `P`. | 8 | | `typename F::reflection_types` | A [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type that contains any number of distinct types `Rs`. Each type `R` in `Rs` shall meet the [*ProReflection* requirements](ProReflection.md) of `P`. | 9 | 10 | ## See Also 11 | 12 | - [concept `proxiable`](proxiable.md) 13 | - [*ProBasicFacade* requirements](ProBasicFacade.md) 14 | -------------------------------------------------------------------------------- /docs/ProOverload.md: -------------------------------------------------------------------------------- 1 | # Named requirements: *ProOverload* 2 | 3 | A type `O` meets the *ProOverload* requirements if `substituted-overload` matches one of the following definitions, where `F` is any type meeting the [*ProBasicFacade* requirements](ProBasicFacade.md), `R` is the *return type*, `Args...` are the *argument types*. 4 | 5 | The exposition-only type `substituted-overload` is `OT` if `O` is a specialization of [`facade_aware_overload_t`](facade_aware_overload_t.md), or `O` otherwise. 6 | 7 | | Definitions of `O` | 8 | | ----------------------------- | 9 | | `R(Args...)` | 10 | | `R(Args...) noexcept` | 11 | | `R(Args...) &` | 12 | | `R(Args...) & noexcept` | 13 | | `R(Args...) &&` | 14 | | `R(Args...) && noexcept` | 15 | | `R(Args...) const` | 16 | | `R(Args...) const noexcept` | 17 | | `R(Args...) const&` | 18 | | `R(Args...) const& noexcept` | 19 | | `R(Args...) const&&` | 20 | | `R(Args...) const&& noexcept` | 21 | 22 | ## See Also 23 | 24 | - [*ProConvention* requirements](ProConvention.md) 25 | - [class template `std::move_only_function`](https://en.cppreference.com/w/cpp/utility/functional/move_only_function) 26 | -------------------------------------------------------------------------------- /docs/ProReflection.md: -------------------------------------------------------------------------------- 1 | # Named requirements: *ProReflection* 2 | 3 | A type `R` meets the *ProReflection* requirements of a type `P` if `R` meets the [*ProBasicReflection* requirements](ProBasicReflection.md), and the following expressions are well-formed and have the specified semantics (let `T` be `P` when `R::is_direct` is `true`, or otherwise `typename std::pointer_traits

::element_type`). 4 | 5 | | Expressions | Semantics | 6 | | --------------------------------------------------- | ------------------------------------------------------------ | 7 | | `typename R::reflector_type{std::in_place_type}` | A [core constant expression](https://en.cppreference.com/w/cpp/language/constant_expression) that constructs a value of type `typename R::reflector_type`, reflecting implementation-defined metadata of type `T`. | 8 | 9 | ## See Also 10 | 11 | - [*ProFacade* requirements](ProFacade.md) 12 | -------------------------------------------------------------------------------- /docs/access_proxy.md: -------------------------------------------------------------------------------- 1 | # Function template `access_proxy` 2 | 3 | ```cpp 4 | template 5 | proxy& access_proxy(A& a) noexcept; 6 | 7 | template 8 | const proxy& access_proxy(const A& a) noexcept; 9 | 10 | template 11 | proxy&& access_proxy(A&& a) noexcept; 12 | 13 | template 14 | const proxy&& access_proxy(const A&& a) noexcept; 15 | ``` 16 | 17 | Accesses a `proxy` object from an [accessor](ProAccessible.md) instantiated from the `proxy`. As per `facade`, `typename F::convention_types` shall be a [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type containing distinct types `Cs`. There shall be a type `C` in `Cs` where `A` is the same type as `typename C::template accessor`. The behavior is undefined if `a` is not instantiated from a `proxy`. 18 | 19 | ## Return Value 20 | 21 | A reference to the `proxy` that has instantiated `a`. 22 | 23 | ## Notes 24 | 25 | Similar to [`proxy_invoke`](proxy_invoke.md), this function can be used to implement the accessibility of `proxy`. If the facade type `F` is defined with the recommended facilities, it has full accessibility support. Specifically, when: 26 | 27 | - the underlying dispatch type `typename C::dispatch_type` is defined via [macro `PRO_DEF_MEM_DISPATCH`](PRO_DEF_MEM_DISPATCH.md), [macro `PRO_DEF_FREE_DISPATCH`](PRO_DEF_FREE_DISPATCH.md), or is a specialization of either [`operator_dispatch`](operator_dispatch.md) or [`conversion_dispatch`](explicit_conversion_dispatch.md), and 28 | - the convention is defined via [`facade_builder`](basic_facade_builder.md). 29 | 30 | ## Example 31 | 32 | ```cpp 33 | #include 34 | #include 35 | 36 | #include 37 | 38 | PRO_DEF_FREE_DISPATCH(FreeToString, std::to_string, ToString); 39 | 40 | struct Stringable : pro::facade_builder 41 | ::add_convention 42 | ::build {}; 43 | 44 | int main() { 45 | pro::proxy p = pro::make_proxy(123); 46 | 47 | // Invokes with accessibility API 48 | std::cout << ToString(*p) << "\n"; // Prints "123" 49 | 50 | // How it works behind the scenes 51 | using Accessor = FreeToString::accessor; 52 | static_assert(std::is_base_of_v>); 53 | Accessor& a = static_cast(*p); 54 | pro::proxy& p2 = pro::access_proxy(a); 55 | std::cout << std::boolalpha << (&p == &p2) << "\n"; // Prints "true" because access_proxy converts 56 | // an accessor back to the original proxy 57 | auto result = pro::proxy_invoke(p2); 58 | std::cout << result << "\n"; // Prints "123" 59 | } 60 | ``` 61 | 62 | ## See Also 63 | 64 | - [named requirements *ProAccessible*](ProAccessible.md) 65 | - [function template `proxy_invoke`](proxy_invoke.md) 66 | -------------------------------------------------------------------------------- /docs/allocate_proxy.md: -------------------------------------------------------------------------------- 1 | # Function template `allocate_proxy` 2 | 3 | The definition of `allocate_proxy` makes use of an exposition-only class template *allocated-ptr*. An object of type `allocated-ptr` allocates the storage for another object of type `T` with an allocator of type `Alloc` and manages the lifetime of this contained object. Similar to [`std::optional`](https://en.cppreference.com/w/cpp/utility/optional), `allocated-ptr` provides `operator*` for accessing the managed object of type `T` with the same qualifiers, but does not necessarily support the state where the contained object is absent. 4 | 5 | ```cpp 6 | // (1) 7 | template 8 | proxy allocate_proxy(const Alloc& alloc, Args&&... args); // freestanding-deleted 9 | 10 | // (2) 11 | template 12 | proxy allocate_proxy(const Alloc& alloc, std::initializer_list il, Args&&... args); // freestanding-deleted 13 | 14 | // (3) 15 | template 16 | proxy allocate_proxy(const Alloc& alloc, T&& value); // freestanding-deleted 17 | ``` 18 | 19 | `(1)` Creates a `proxy` object containing a value `p` of type `allocated-ptr`, where `*p` is direct-non-list-initialized with `std::forward(args)...`. 20 | 21 | `(2)` Creates a `proxy` object containing a value `p` of type `allocated-ptr`, where `*p` is direct-non-list-initialized with `il, std::forward(args)...`. 22 | 23 | `(3)` Creates a `proxy` object containing a value `p` of type `allocated-ptr, Alloc>`, where `*p` is direct-non-list-initialized with `std::forward(value)`. 24 | 25 | *Since 3.3.0*: For `(1-3)`, if [`proxiable_target, F>`](proxiable_target.md) is `false`, the program is ill-formed and diagnostic messages are generated. 26 | 27 | ## Return Value 28 | 29 | The constructed `proxy` object. 30 | 31 | ## Exceptions 32 | 33 | Throws any exception thrown by allocation or the constructor of `T`. 34 | 35 | ## Notes 36 | 37 | The implementation of `allocated-ptr` may vary depending on the definition of `F`. Specifically, when `F::constraints.max_size` and `F::constraints.max_align` are not large enough to hold both a pointer to the allocated memory and a copy of the allocator, `allocated-ptr` shall allocate additional storage for the allocator. 38 | 39 | ## Example 40 | 41 | ```cpp 42 | #include 43 | 44 | #include 45 | 46 | // By default, the maximum pointer size defined by pro::facade_builder 47 | // is 2 * sizeof(void*). This value can be overridden by `restrict_layout`. 48 | struct Any : pro::facade_builder::build {}; 49 | 50 | int main() { 51 | // sizeof(std::array) is usually greater than 2 * sizeof(void*), 52 | // calling allocate_proxy has no limitation to the size and alignment of the target 53 | using Target = std::array; 54 | pro::proxy p1 = pro::allocate_proxy(std::allocator{}); 55 | } 56 | ``` 57 | 58 | ## See Also 59 | 60 | - [function template `make_proxy`](make_proxy.md) 61 | - [named requirements *Allocator*](https://en.cppreference.com/w/cpp/named_req/Allocator) 62 | -------------------------------------------------------------------------------- /docs/allocate_proxy_shared.md: -------------------------------------------------------------------------------- 1 | # Function template `allocate_proxy_shared` 2 | 3 | The definition of `allocate_proxy_shared` makes use of exposition-only class templates *strong-compact-ptr* and *weak-compact-ptr*. Their semantics are similar to [`std::shared_ptr`](https://en.cppreference.com/w/cpp/memory/shared_ptr) and [`std::weak_ptr`](https://en.cppreference.com/w/cpp/memory/weak_ptr), but do not provide a polymorphic deleter. Their size and alignment are guaranteed not to be greater than those of a raw pointer type. `strong-compact-ptr` is conditionally convertible to `weak-compact-ptr` only if necessary. Similar to [`std::optional`](https://en.cppreference.com/w/cpp/utility/optional), `strong-compact-ptr` provides `operator*` for accessing the managed object of type `T` with the same qualifiers. 4 | 5 | ```cpp 6 | // (1) 7 | template 8 | proxy allocate_proxy_shared(const Alloc& alloc, Args&&... args); // freestanding-deleted 9 | 10 | // (2) 11 | template 12 | proxy allocate_proxy_shared(const Alloc& alloc, std::initializer_list il, Args&&... args); // freestanding-deleted 13 | 14 | // (3) 15 | template 16 | proxy allocate_proxy_shared(const Alloc& alloc, T&& value); // freestanding-deleted 17 | ``` 18 | 19 | `(1)` Creates a `proxy` object containing a value `p` of type `strong-compact-ptr`, where `*p` is direct-non-list-initialized with `std::forward(args)...`. 20 | 21 | `(2)` Creates a `proxy` object containing a value `p` of type `strong-compact-ptr`, where `*p` is direct-non-list-initialized with `il, std::forward(args)...`. 22 | 23 | `(3)` Creates a `proxy` object containing a value `p` of type `strong-compact-ptr, Alloc>`, where `*p` is direct-non-list-initialized with `std::forward(value)`. 24 | 25 | For `(1-3)`, if [`proxiable_target, F>`](proxiable_target.md) is `false`, the program is ill-formed and diagnostic messages are generated. 26 | 27 | ## Return Value 28 | 29 | The constructed `proxy` object. 30 | 31 | ## Exceptions 32 | 33 | Throws any exception thrown by allocation or the constructor of `T`. 34 | 35 | ## Notes 36 | 37 | The implementation of `strong-compact-ptr` may vary depending on the definition of `F`. Specifically, when `F` does not support weak ownership via [`basic_facade_builder::support_weak`](basic_facade_builder/support_weak.md), `strong-compact-ptr` is not convertible to `weak-compact-ptr`, which leaves more room for optimization. 38 | 39 | ## Example 40 | 41 | ```cpp 42 | #include 43 | #include 44 | 45 | #include 46 | 47 | struct RttiAware : pro::facade_builder 48 | ::support_copy 49 | ::support 50 | ::build {}; 51 | 52 | int main() { 53 | std::pmr::unsynchronized_pool_resource pool; 54 | std::pmr::polymorphic_allocator<> alloc{&pool}; 55 | pro::proxy p1 = pro::allocate_proxy_shared(alloc, 1); 56 | pro::proxy p2 = p1; 57 | proxy_cast(*p1) += 2; 58 | std::cout << proxy_cast(*p2) << "\n"; // Prints "3" 59 | } 60 | ``` 61 | 62 | ## See Also 63 | 64 | - [function template `allocate_proxy`](allocate_proxy.md) 65 | - [named requirements *Allocator*](https://en.cppreference.com/w/cpp/named_req/Allocator) -------------------------------------------------------------------------------- /docs/bad_proxy_cast.md: -------------------------------------------------------------------------------- 1 | # Class `bad_proxy_cast` 2 | 3 | ```cpp 4 | class bad_proxy_cast : public std::bad_cast; // since 3.2.0 5 | ``` 6 | 7 | A type of object to be thrown by the value-returning forms of [`proxy_cast`](basic_facade_builder/support_rtti.md) on failure. 8 | 9 | ## Member Functions 10 | 11 | | Name | Description | 12 | | ------------- | ------------------------------------ | 13 | | (constructor) | constructs a `bad_proxy_cast` object | 14 | | (destructor) | destroys a `bad_proxy_cast` object | 15 | | `what` | returns the explanatory string | 16 | -------------------------------------------------------------------------------- /docs/basic_facade_builder/add_convention.md: -------------------------------------------------------------------------------- 1 | # `basic_facade_builder::add_convention`
`basic_facade_builder::add_direct_convention`
`basic_facade_builder::add_indirect_convention` 2 | 3 | ```cpp 4 | template requires(/* see below */) 5 | using add_convention = add_indirect_convention; 6 | 7 | template requires(/* see below */) 8 | using add_indirect_convention = basic_facade_builder; 9 | 10 | template requires(/* see below */) 11 | using add_direct_convention = basic_facade_builder; 12 | ``` 13 | 14 | The alias templates `add_convention`, `add_indirect_convention`, and `add_direct_convention` of `basic_facade_builder` add convention types to the template parameters. The expression inside `requires` is equivalent to `sizeof...(Os) > 0u` and each type in `Os` meets the [*ProOverload* requirements](../ProOverload.md). Let `F` be a facade type, 15 | 16 | - `add_convention` is equivalent to `add_indirect_convention`. 17 | - `add_indirect_convention` merges an implementation-defined convention type `IC` into `Cs`, where: 18 | - `IC::is_direct` is `false`. 19 | - `typename IC::dispatch_type` is `D`. 20 | - `typename IC::overload_types` is a [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type of distinct types in `Os`. 21 | - `typename IC::template accessor` is `typename D::template accessor`](../ProOverload.md)`...>` if applicable. 22 | - `add_direct_convention` merges an implementation-defined convention type `IC` into `Cs`, where: 23 | - `IC::is_direct` is `true`. 24 | - `typename IC::dispatch_type` is `D`. 25 | - `typename IC::overload_types` is a [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type of distinct types in `Os`. 26 | - `typename IC::template accessor` is `typename D::template accessor`](../ProOverload.md)`...>` if applicable. 27 | 28 | When `Cs` already contains a convention type `IC2` where `IC2::is_direct == IC::is_direct && std::is_same_v` is `true`, `Os` merges with `typename IC2::overload_types` and removes duplicates, and `std::tuple_size_v` shall not change. 29 | 30 | ## Notes 31 | 32 | Adding duplicated combinations of some dispatch type and overload type is well-defined (either directly via `add_convention`, `add_indirect_convention`, `add_direct_convention`, or indirectly via [`add_facade`](add_facade.md)), and does not have side-effects to [`build`](build.md) at either compile-time or runtime. 33 | 34 | ## Example 35 | 36 | ```cpp 37 | #include 38 | #include 39 | #include 40 | 41 | #include 42 | 43 | PRO_DEF_FREE_DISPATCH(FreeToString, std::to_string, ToString); 44 | 45 | struct BasicStringable : pro::facade_builder 46 | ::add_convention 47 | ::build {}; 48 | 49 | struct Stringable : pro::facade_builder 50 | ::add_facade 51 | ::support_copy 52 | ::add_direct_convention() &&> 53 | ::build {}; 54 | 55 | int main() { 56 | pro::proxy p1 = std::make_shared(123); 57 | pro::proxy p2 = p1; 58 | pro::proxy p3 = static_cast>(std::move(p2)); 59 | pro::proxy p4 = std::move(p3); 60 | // pro::proxy p5 = p4; // Won't compile 61 | std::cout << ToString(*p4) << "\n"; // Prints "123" 62 | std::cout << std::boolalpha << p3.has_value() << "\n"; // Prints "false" 63 | } 64 | ``` 65 | 66 | ## See Also 67 | 68 | - [macro `PRO_DEF_MEM_DISPATCH`](../PRO_DEF_MEM_DISPATCH.md) 69 | - [macro `PRO_DEF_FREE_DISPATCH`](../PRO_DEF_FREE_DISPATCH.md) 70 | - [class template `operator_dispatch`](../operator_dispatch.md) 71 | - [class `conversion_dispatch`](../explicit_conversion_dispatch.md) 72 | -------------------------------------------------------------------------------- /docs/basic_facade_builder/add_facade.md: -------------------------------------------------------------------------------- 1 | # `basic_facade_builder::add_facade` 2 | 3 | ```cpp 4 | template 5 | using add_facade = basic_facade_builder; 6 | ``` 7 | 8 | The alias template `add_facade` of `basic_facade_builder` adds a [facade](../facade.md) type into the template parameters. It merges `typename F::convention_types` into `Cs`, `typename F::reflection_types` into `Rs`, and `F::constraints` into `C`. Optionally, it adds a convention for implicit upward conversion into `Cs` when `WithUpwardConversion` is `true`. 9 | 10 | ## Notes 11 | 12 | Adding a facade type that contains duplicated convention or reflection types already defined in `Cs` or `Rs` is well-defined and does not have side effects on [`build`](build.md) at either compile-time or runtime. By default, `WithUpwardConversion` is `false`, which guarantees minimal binary size in code generation. However, upward conversion is helpful when an API requires backward compatibility. Users can opt-in to this feature by specifying `true` as the second parameter of `add_facade`, at the cost of potentially a slightly larger binary size. 13 | 14 | ## Example 15 | 16 | ```cpp 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | PRO_DEF_MEM_DISPATCH(MemSize, size); 23 | PRO_DEF_MEM_DISPATCH(MemAt, at); 24 | PRO_DEF_MEM_DISPATCH(MemEmplace, emplace); 25 | 26 | struct Copyable : pro::facade_builder 27 | ::support_copy 28 | ::build {}; 29 | 30 | struct BasicContainer : pro::facade_builder 31 | ::add_convention 32 | ::build {}; 33 | 34 | struct StringDictionary : pro::facade_builder 35 | ::add_facade 36 | ::add_facade 37 | ::add_convention 38 | ::build {}; 39 | 40 | struct MutableStringDictionary : pro::facade_builder 41 | ::add_facade 42 | ::add_convention 43 | ::build {}; 44 | 45 | int main() { 46 | pro::proxy p1 = 47 | pro::make_proxy>(); 48 | std::cout << p1->size() << "\n"; // Prints "0" 49 | try { 50 | std::cout << p1->at(123) << "\n"; // No output because the expression throws 51 | } catch (const std::out_of_range& e) { 52 | std::cerr << e.what() << "\n"; // Prints error message 53 | } 54 | p1->emplace(123, "lalala"); 55 | auto p2 = p1; // Performs a deep copy 56 | p2->emplace(456, "trivial"); 57 | pro::proxy p3 = std::move(p2); // Performs an upward conversion from an rvalue reference 58 | std::cout << p1->size() << "\n"; // Prints "1" 59 | std::cout << p1->at(123) << "\n"; // Prints "lalala" 60 | std::cout << std::boolalpha << p2.has_value() << "\n"; // Prints "false" because it is moved 61 | std::cout << p3->size() << "\n"; // Prints "2" 62 | std::cout << p3->at(123) << "\n"; // Prints "lalala" 63 | std::cout << p3->at(456) << "\n"; // Prints "trivial" 64 | } 65 | ``` 66 | 67 | ## See Also 68 | 69 | - [`build`](build.md) 70 | -------------------------------------------------------------------------------- /docs/basic_facade_builder/add_reflection.md: -------------------------------------------------------------------------------- 1 | # `basic_facade_builder::add_reflection`
`basic_facade_builder::add_direct_reflection`
`basic_facade_builder::add_indirect_reflection` 2 | 3 | ```cpp 4 | template 5 | using add_reflection = add_indirect_reflection; 6 | 7 | template 8 | using add_indirect_reflection = basic_facade_builder; 9 | 10 | template 11 | using add_direct_reflection = basic_facade_builder; 12 | ``` 13 | 14 | The alias templates `add_reflection`, `add_indirect_reflection` and `add_direct_reflection` of `basic_facade_builder` add reflection types to the template parameters. Specifically, 15 | 16 | - `add_reflection` is equivalent to `add_indirect_reflection`. 17 | - `add_indirect_reflection` merges an implementation-defined reflection type `Refl` into `Rs`, where: 18 | - `Refl::is_direct` is `false`. 19 | - `typename Refl::reflector_type` is `R`. 20 | - `typename Refl::template accessor` is `typename R::template accessor` if applicable. 21 | - `add_direct_reflection` merges an implementation-defined reflection type `Refl` into `Rs`, where: 22 | - `Refl::is_direct` is `true`. 23 | - `typename Refl::reflector_type` is `R`. 24 | - `typename Refl::template accessor` is `typename R::template accessor` if applicable. 25 | 26 | When `Rs` already contains `Refl`, the template parameters shall not change. 27 | 28 | ## Notes 29 | 30 | Adding duplicate reflection types is well-defined, whether done directly via `add_reflection`, `add_indirect_reflection`, `add_direct_reflection`, or indirectly via [`add_facade`](add_facade.md). This process does not affect the behavior of [`build`](build.md) at either compile-time or runtime. 31 | 32 | ## Example 33 | 34 | ```cpp 35 | #include 36 | #include 37 | 38 | #include 39 | 40 | struct LayoutReflector { 41 | public: 42 | template 43 | constexpr explicit LayoutReflector(std::in_place_type_t) 44 | : Size(sizeof(T)), Align(alignof(T)) {} 45 | 46 | template 47 | struct accessor { 48 | friend std::size_t SizeOf(const std::conditional_t, 49 | pro::proxy_indirect_accessor>& self) noexcept { 50 | const LayoutReflector& refl = pro::proxy_reflect(pro::access_proxy(self)); 51 | return refl.Size; 52 | } 53 | 54 | friend std::size_t AlignOf(const std::conditional_t, 55 | pro::proxy_indirect_accessor>& self) noexcept { 56 | const LayoutReflector& refl = pro::proxy_reflect(pro::access_proxy(self)); 57 | return refl.Align; 58 | } 59 | }; 60 | 61 | std::size_t Size, Align; 62 | }; 63 | 64 | struct LayoutAware : pro::facade_builder 65 | ::add_direct_reflection 66 | ::add_indirect_reflection 67 | ::build {}; 68 | 69 | int main() { 70 | int a = 123; 71 | pro::proxy p = &a; 72 | std::cout << SizeOf(p) << "\n"; // Prints sizeof(raw pointer) 73 | std::cout << AlignOf(p) << "\n"; // Prints alignof(raw pointer) 74 | std::cout << SizeOf(*p) << "\n"; // Prints sizeof(int) 75 | std::cout << AlignOf(*p) << "\n"; // Prints alignof(int) 76 | 77 | p = pro::make_proxy(123); // SBO enabled 78 | std::cout << SizeOf(p) << "\n"; // Prints sizeof(int) 79 | std::cout << AlignOf(p) << "\n"; // Prints alignof(int) 80 | std::cout << SizeOf(*p) << "\n"; // Prints sizeof(int) 81 | std::cout << AlignOf(*p) << "\n"; // Prints alignof(int) 82 | 83 | p = pro::make_proxy>(); // SBO disabled 84 | std::cout << SizeOf(p) << "\n"; // Prints sizeof(raw pointer) 85 | std::cout << AlignOf(p) << "\n"; // Prints alignof(raw pointer) 86 | std::cout << SizeOf(*p) << "\n"; // Prints "100" 87 | std::cout << AlignOf(*p) << "\n"; // Prints "1" 88 | } 89 | ``` 90 | 91 | ## See Also 92 | 93 | - [named requirements: *ProReflection*](../ProReflection.md) 94 | -------------------------------------------------------------------------------- /docs/basic_facade_builder/build.md: -------------------------------------------------------------------------------- 1 | # `basic_facade_builder::build` 2 | 3 | ```cpp 4 | using build = /* see below */; 5 | ``` 6 | 7 | Specifies a [facade](../facade.md) type deduced from the template parameters of `basic_facade_builder`. Specifically, 8 | 9 | - `typename build::convention_types` is defined as `Cs`, and 10 | - `typename build::reflection_types` is defined as `Rs`, and 11 | - `build::constraints` is a [core constant expression](https://en.cppreference.com/w/cpp/language/constant_expression) of type [`proxiable_ptr_constraints`](../proxiable_ptr_constraints.md) that defines constraints to the pointer types, and 12 | - `build::constraints.max_size` is `C::max_size` if defined by [`restrict_layout`](restrict_layout.md), otherwise `sizeof(void*) * 2u` when `C::max_size` is *default-size*, and 13 | - `build::constraints.max_align` is `C::max_align` if defined by [`restrict_layout`](restrict_layout.md), otherwise `alignof(void*)` when `C::max_align` is *default-size*, and 14 | - `build::constraints.copyability` is `C::copyability` if defined by [`support_copy`](support_copy.md), otherwise `constraint_level::none` when `C::copyability` is *default-cl*, and 15 | - `build::constraints.relocatability` is `C::relocatability` if defined by [`support_rellocation`](support_relocation.md), otherwise `constraint_level::nothrow` when `C::relocatability` is *default-cl*, and 16 | - `build::constraints.destructibility` is `C::destructibility` if defined by [`support_destruction`](support_destruction.md), otherwise `constraint_level::nothrow` when `C::destructibility` is *default-cl*. 17 | 18 | The definition of type `build` makes use of the following exposition-only function: 19 | 20 | ```cpp 21 | consteval proxiable_ptr_constraints normalize(proxiable_ptr_constraints value) { 22 | if (value.max_size == default-size) 23 | { value.max_size = sizeof(void*) * 2u; } 24 | if (value.max_align == default-size) 25 | { value.max_align = alignof(void*); } 26 | if (value.copyability == default-cl) 27 | { value.copyability = constraint_level::none; } 28 | if (value.relocatability == default-cl) 29 | { value.relocatability = constraint_level::nothrow; } 30 | if (value.destructibility == default-cl) 31 | { value.destructibility = constraint_level::nothrow; } 32 | return value; 33 | } 34 | ``` 35 | 36 | ## Member Types 37 | 38 | | Name | Definition | 39 | | ------------------ | ---------- | 40 | | `convention_types` | `Cs` | 41 | | `reflection_types` | `Rs` | 42 | 43 | ## Member Constants 44 | 45 | | Name | Definition | 46 | | ---------------------------------- | -------------- | 47 | | `constraints` [static] [constexpr] | `normalize(C)` | 48 | 49 | ## Notes 50 | 51 | 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. 52 | 53 | 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. 54 | 55 | ## Example 56 | 57 | ```cpp 58 | #include 59 | 60 | #include 61 | 62 | struct DefaultBase : pro::facade_builder 63 | ::build {}; 64 | 65 | struct CopyableBase : pro::facade_builder 66 | ::support_copy 67 | ::build {}; 68 | 69 | struct TrivialBase : pro::facade_builder 70 | ::support_copy 71 | ::support_relocation 72 | ::support_destruction 73 | ::restrict_layout 74 | ::build {}; 75 | 76 | int main() { 77 | static_assert(!std::is_copy_constructible_v>); 78 | static_assert(std::is_nothrow_move_constructible_v>); 79 | static_assert(std::is_nothrow_destructible_v>); 80 | 81 | static_assert(std::is_copy_constructible_v>); 82 | static_assert(std::is_nothrow_move_constructible_v>); 83 | static_assert(std::is_nothrow_destructible_v>); 84 | 85 | static_assert(std::is_trivially_copy_constructible_v>); 86 | static_assert(std::is_trivially_move_constructible_v>); 87 | static_assert(std::is_trivially_destructible_v>); 88 | } 89 | ``` 90 | 91 | ## See Also 92 | 93 | - [class template `proxy`](../proxy.md) 94 | -------------------------------------------------------------------------------- /docs/basic_facade_builder/restrict_layout.md: -------------------------------------------------------------------------------- 1 | # `basic_facade_builder::restrict_layout` 2 | 3 | ```cpp 4 | template 5 | requires(std::has_single_bit(PtrAlign) && PtrSize % PtrAlign == 0u) 6 | using restrict_layout = basic_facade_builder; 7 | ``` 8 | 9 | The alias template `restrict_layout` of `basic_facade_builder` adds layout restrictions to the template parameters, specifically `C::max_size` and `C::max_align`. The default value of `PtrAlign` is the maximum possible alignment of an object of size `PtrSize`, not greater than `alignof(std::max_align_t`). After applying the restriction, `C::max_size` becomes `std::min(C::max_size, PtrSize)`, and `C::max_align` becomes `std::min(C::max_align, PtrAlign)`. 10 | 11 | ## Notes 12 | 13 | If no layout restriction is applied before specifying [`build`](build.md), the default value of `build::constraints.max_size` is `sizeof(void*) * 2`, and the default value of `build::constraints.max_align` is `alignof(void*)`. 14 | 15 | ## Example 16 | 17 | ```cpp 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | struct DefaultFacade : pro::facade_builder::build {}; 24 | 25 | struct SmallFacade : pro::facade_builder 26 | ::restrict_layout 27 | ::build {}; 28 | 29 | int main() { 30 | static_assert(sizeof(pro::proxy) > sizeof(pro::proxy)); 31 | static_assert(pro::proxiable, DefaultFacade>); 32 | static_assert(pro::proxiable, SmallFacade>); 33 | static_assert(pro::proxiable, DefaultFacade>); 34 | static_assert(!pro::proxiable, SmallFacade>); 35 | static_assert(pro::inplace_proxiable_target, DefaultFacade>); 36 | static_assert(!pro::inplace_proxiable_target, SmallFacade>); 37 | static_assert(!pro::inplace_proxiable_target, DefaultFacade>); 38 | static_assert(!pro::inplace_proxiable_target, SmallFacade>); 39 | pro::proxy p1 = std::make_shared(123); 40 | // pro::proxy p2 = std::make_shared(123); // Won't compile 41 | } 42 | ``` 43 | 44 | ## See Also 45 | 46 | - [`build`](build.md) 47 | - [concept `inplace_proxiable_target`](../inplace_proxiable_target.md) 48 | -------------------------------------------------------------------------------- /docs/basic_facade_builder/support_copy.md: -------------------------------------------------------------------------------- 1 | # `basic_facade_builder::support_copy` 2 | 3 | ```cpp 4 | template 5 | using support_copy = basic_facade_builder; 6 | ``` 7 | 8 | The alias template `support_copy` of `basic_facade_builder` adds copyability support to the template parameters, specifically `C::copyability`. After the operation, `C::copyability` becomes `std::max(C::copyability, CL)`. 9 | 10 | ## Notes 11 | 12 | If no copyability support is applied before specifying [`build`](build.md), the default value of `build::constraints.copyability` is `pro::constraint_level::none`. 13 | 14 | ## Example 15 | 16 | ```cpp 17 | #include 18 | 19 | #include 20 | 21 | struct Movable : pro::facade_builder::build {}; 22 | 23 | struct Copyable : pro::facade_builder 24 | ::support_copy 25 | ::build {}; 26 | 27 | int main() { 28 | pro::proxy p1 = std::make_unique(123); 29 | // pro::proxy p2 = std::make_unique(123); // Won't compile 30 | pro::proxy p3 = std::make_shared(456); 31 | // auto p4 = p1; // Won't compile 32 | auto p5 = p3; 33 | } 34 | ``` 35 | 36 | ## See Also 37 | 38 | - [`support_relocation`](support_relocation.md) 39 | -------------------------------------------------------------------------------- /docs/basic_facade_builder/support_destruction.md: -------------------------------------------------------------------------------- 1 | # `basic_facade_builder::support_destruction` 2 | 3 | ```cpp 4 | template 5 | using support_destruction = basic_facade_builder; 6 | ``` 7 | 8 | The alias template `support_destruction` of `basic_facade_builder` adds destruction support to the template parameters, specifically `C::destructibility`. After the operation, `C::destructibility` becomes `std::max(C::destructibility, CL)`. 9 | 10 | ## Notes 11 | 12 | If no destructibility support is applied before specifying [`build`](build.md), the default value of `build::constraints.destructibility` is `pro::constraint_level::nothrow`. 13 | 14 | ## Example 15 | 16 | ```cpp 17 | #include 18 | 19 | #include 20 | 21 | struct Movable : pro::facade_builder::build {}; 22 | 23 | struct NonriviallyDestructible : pro::facade_builder 24 | ::support_relocation 25 | ::support_destruction 26 | ::build {}; 27 | 28 | int main() { 29 | static_assert(std::is_nothrow_destructible_v>); 30 | static_assert(!std::is_nothrow_destructible_v>); 31 | } 32 | ``` 33 | 34 | ## See Also 35 | 36 | - [`support_relocation`](support_relocation.md) 37 | -------------------------------------------------------------------------------- /docs/basic_facade_builder/support_format.md: -------------------------------------------------------------------------------- 1 | # `basic_facade_builder::support_format`
`basic_facade_builder::support_wformat` 2 | 3 | ```cpp 4 | using support_format = basic_facade_builder; // since 3.2.0 5 | 6 | using support_wformat = basic_facade_builder; // since 3.2.0 7 | ``` 8 | 9 | The member types `support_format` and `support_wformat` of `basic_facade_builder` add necessary convention and reflection types to the template parameters, enabling specializations of [`std::formatter, 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). 10 | 11 | `support_format` and `support_wformat` also add constraints to a facade type `F` built from `basic_facade_builder`, requiring a contained value of `proxy` be *formattable*. Formally, let `p` be a contained value of `proxy`, `CharT` be `char` (if `support_format` is specified) or `wchar_t` (if `support_wformat` is specified), `T` be `std::decay_t`, `std::formatter` shall be an enabled specialization of `std::formatter`. 12 | 13 | ## Example 14 | 15 | ```cpp 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | struct Formattable : pro::facade_builder 22 | ::support 23 | ::build {}; 24 | 25 | int main() { 26 | pro::proxy p = pro::make_proxy(123); 27 | std::cout << std::format("{}", *p) << "\n"; // Prints "123" 28 | std::cout << std::format("{:*<6}", *p) << "\n"; // Prints "123***" 29 | } 30 | ``` 31 | 32 | ## See Also 33 | 34 | - [class template `std::formatter`](../formatter_proxy_indirect_accessor.md) 35 | -------------------------------------------------------------------------------- /docs/basic_facade_builder/support_relocation.md: -------------------------------------------------------------------------------- 1 | # `basic_facade_builder::support_relocation` 2 | 3 | ```cpp 4 | template 5 | using support_relocation = basic_facade_builder; 6 | ``` 7 | 8 | The alias template `support_relocation` of `basic_facade_builder` adds relocatability support to the template parameters, specifically `C::relocatability`. After the operation, `C::relocatability` becomes `std::max(C::relocatability, CL)`. 9 | 10 | ## Notes 11 | 12 | If no relocatability support is applied before specifying [`build`](build.md), the default value of `build::constraints.relocatability` is `pro::constraint_level::nothrow`. 13 | 14 | ## Example 15 | 16 | ```cpp 17 | #include 18 | 19 | #include 20 | 21 | struct Movable : pro::facade_builder::build {}; 22 | 23 | struct Trivial : pro::facade_builder 24 | ::support_copy 25 | ::support_relocation 26 | ::support_destruction 27 | ::build {}; 28 | 29 | int main() { 30 | pro::proxy p1 = std::make_unique(123); 31 | // pro::proxy p2 = std::make_unique(456); // Won't compile 32 | double v = 3.14; 33 | pro::proxy p3 = &v; // Compiles because double* is trivial 34 | } 35 | ``` 36 | 37 | ## See Also 38 | 39 | - [`support_copy`](support_copy.md) 40 | -------------------------------------------------------------------------------- /docs/basic_facade_builder/support_rtti.md: -------------------------------------------------------------------------------- 1 | # `basic_facade_builder::support_rtti`
`basic_facade_builder::support_indirect_rtti`
`basic_facade_builder::support_direct_rtti` 2 | 3 | ```cpp 4 | using support_rtti = support_indirect_rtti; // since 3.2.0 5 | 6 | using support_indirect_rtti = basic_facade_builder; // since 3.2.0 7 | 8 | using support_direct_rtti = basic_facade_builder; // since 3.2.0 9 | ``` 10 | 11 | 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`](../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`](../proxy_indirect_accessor.md) (if `support_rtti` or `support_indirect_rtti` is specified) or [`proxy`](../proxy.md) (if `support_direct_rtti` is specified). 12 | 13 | ## Non-Member Functions 14 | 15 | | Name | Description | 16 | | ---------------------------------------------- | ------------------------------------------ | 17 | | [`proxy_typeid`](support_rtti/proxy_typeid.md) | returns the `typeid` of the contained type | 18 | | [`proxy_cast`](support_rtti/proxy_cast.md) | type-safe access to the contained object | 19 | 20 | ## Example 21 | 22 | ```cpp 23 | #include 24 | 25 | #include 26 | 27 | struct RttiAware : pro::facade_builder 28 | ::support 29 | ::support 30 | ::build {}; 31 | 32 | int main() { 33 | int v = 123; 34 | pro::proxy p = &v; 35 | std::cout << proxy_typeid(p).name() << "\n"; // Prints "Pi" (assuming GCC) 36 | std::cout << proxy_cast(p) << "\n"; // Prints the address of v 37 | std::cout << proxy_typeid(*p).name() << "\n"; // Prints "i" (assuming GCC) 38 | std::cout << proxy_cast(*p) << "\n"; // Prints "123" 39 | } 40 | ``` 41 | 42 | ## See Also 43 | 44 | - [`support_view`](support_view.md) 45 | -------------------------------------------------------------------------------- /docs/basic_facade_builder/support_rtti/proxy_cast.md: -------------------------------------------------------------------------------- 1 | # Function template `proxy_cast` 2 | 3 | ```cpp 4 | // (1) 5 | template 6 | T proxy_cast(const proxy_indirect_accessor& operand); 7 | 8 | // (2) 9 | template 10 | T proxy_cast(proxy_indirect_accessor& operand); 11 | 12 | // (3) 13 | template 14 | T proxy_cast(proxy_indirect_accessor&& operand); 15 | 16 | // (4) 17 | template 18 | T proxy_cast(const proxy& operand); 19 | 20 | // (5) 21 | template 22 | T proxy_cast(proxy& operand); 23 | 24 | // (6) 25 | template 26 | T proxy_cast(proxy&& operand); 27 | 28 | // (7) 29 | template 30 | const T* proxy_cast(const proxy_indirect_accessor* operand) noexcept; 31 | 32 | // (8) 33 | template 34 | T* proxy_cast(proxy_indirect_accessor* operand) noexcept; 35 | 36 | // (9) 37 | template 38 | const T* proxy_cast(const proxy* operand) noexcept; 39 | 40 | // (10) 41 | template 42 | T* proxy_cast(proxy* operand) noexcept; 43 | ``` 44 | 45 | Performs type-safe access to the contained object of `proxy` where `F` is a [facade](../../facade.md) type built from `basic_facade_builder`. 46 | 47 | - `(1-3)` Let `p` be [`access_proxy`](../../access_proxy.md)`(operand)`, `ptr` be the contained value of `p` (if any). If `p` does not contain a value or `std::is_same_v, std::decay_t>` is `false`, throws [`bad_proxy_cast`](../../bad_proxy_cast.md). Otherwise, returns `static_cast(expr)`. Specifically, `expr` is defined as 48 | - `(1)`: `*std::as_const(ptr)`. 49 | - `(2)`: `*ptr`. 50 | - `(3)`: `*std::move(ptr)`. 51 | - `(4-6)` Let `ptr` be the contained value of `operand` (if any). If `operand` does not contain a value or `std::is_same_v, std::decay_t>` is `false`, throws [`bad_proxy_cast`](../../bad_proxy_cast.md). Otherwise, returns `static_cast(expr)`. Specifically, `expr` is defined as 52 | - `(6)`: `std::as_const(ptr)`. 53 | - `(7)`: `ptr`. 54 | - `(8)`: `std::move(ptr)`. 55 | - `(7-10)` Returns `&proxy_cast(*operand)` if the evaluation won't throw, or otherwise, returns `nullptr`. 56 | 57 | These functions are not visible to ordinary [unqualified](https://en.cppreference.com/w/cpp/language/unqualified_lookup) or [qualified lookup](https://en.cppreference.com/w/cpp/language/qualified_lookup). It can only be found by [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl) when `proxy_indirect_accessor` (if `support_rtti` or `support_indirect_rtti` is specified) or `proxy` (if `support_direct_rtti` is specified) is an associated class of the arguments. Usage of these functions is similar to [`std::any_cast`](https://en.cppreference.com/w/cpp/utility/any/any_cast). 58 | 59 | ## Example 60 | 61 | ```cpp 62 | #include 63 | 64 | #include 65 | 66 | struct RttiAware : pro::facade_builder 67 | ::support 68 | ::build {}; 69 | 70 | int main() { 71 | int v = 123; 72 | pro::proxy p; 73 | try { 74 | proxy_cast(*p); // Throws 75 | } catch (const pro::bad_proxy_cast& e) { 76 | std::cout << e.what() << "\n"; // Prints an explanatory string 77 | } 78 | p = &v; 79 | std::cout << proxy_cast(*p) << "\n"; // Prints "123" 80 | proxy_cast(*p) = 456; 81 | std::cout << v << "\n"; // Prints "456" 82 | try { 83 | proxy_cast(*p); // Throws 84 | } catch (const pro::bad_proxy_cast& e) { 85 | std::cout << e.what() << "\n"; // Prints an explanatory string 86 | } 87 | int* ptr1 = proxy_cast(&*p); 88 | std::cout << ptr1 << "\n"; // Prints an address 89 | std::cout << &v << "\n"; // Prints the same address as above 90 | double* ptr2 = proxy_cast(&*p); 91 | std::cout << ptr2 << "\n"; // Prints "0" 92 | } 93 | ``` 94 | 95 | ## See Also 96 | 97 | - [function `proxy_typeid`](proxy_typeid.md) 98 | -------------------------------------------------------------------------------- /docs/basic_facade_builder/support_rtti/proxy_typeid.md: -------------------------------------------------------------------------------- 1 | # Function `proxy_typeid` 2 | 3 | ```cpp 4 | // (1) 5 | const std::type_info& proxy_typeid(const proxy_indirect_accessor& operand) noexcept; 6 | 7 | // (2) 8 | const std::type_info& proxy_typeid(const proxy& operand) noexcept; 9 | ``` 10 | 11 | Returns the `typeid` of the contained type of `proxy` where `F` is a [facade](../../facade.md) type built from `basic_facade_builder`. 12 | 13 | - `(1)` Let `p` be [`access_proxy`](../../access_proxy.md)`(operand)`, `ptr` be the contained value of `p` (if any). Returns `typeid(std::decay_t)` if `p` contains a value, or otherwise, `typeid(void)`. 14 | - `(2)` Let `ptr` be the contained value of `operand` (if any). Returns `typeid(std::decay_t)` if `operand` contains a value `ptr`, or otherwise, `typeid(void)`. 15 | 16 | These functions are not visible to ordinary [unqualified](https://en.cppreference.com/w/cpp/language/unqualified_lookup) or [qualified lookup](https://en.cppreference.com/w/cpp/language/qualified_lookup). It can only be found by [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl) when `proxy_indirect_accessor` (if `support_rtti` or `support_indirect_rtti` is specified) or `proxy` (if `support_direct_rtti` is specified) is an associated class of the arguments. 17 | 18 | ## Example 19 | 20 | ```cpp 21 | #include 22 | 23 | #include 24 | 25 | struct RttiAware : pro::facade_builder 26 | ::support 27 | ::build {}; 28 | 29 | int main() { 30 | pro::proxy p; 31 | std::cout << proxy_typeid(*p).name() << "\n"; // Prints "v" (assuming GCC) 32 | p = pro::make_proxy(123); 33 | std::cout << proxy_typeid(*p).name() << "\n"; // Prints "i" (assuming GCC) 34 | } 35 | ``` 36 | 37 | ## See Also 38 | 39 | - [function template `proxy_cast`](proxy_cast.md) 40 | -------------------------------------------------------------------------------- /docs/basic_facade_builder/support_view.md: -------------------------------------------------------------------------------- 1 | # `basic_facade_builder::support_view` 2 | 3 | ```cpp 4 | using support_view = basic_facade_builder; 5 | ``` 6 | 7 | The member type `support_view` of `basic_facade_builder` adds necessary convention types to allow implicit conversion from [`proxy`](../proxy.md)`` to [`proxy_view`](../proxy_view.md)`` where `F` is a [facade](../facade.md) type built from `basic_facade_builder`. 8 | 9 | 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 raw-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. 10 | 11 | ## Notes 12 | 13 | `support_view` is useful when a certain context does not take ownership of a `proxy` object. Similar to [`std::unique_ptr::get`](https://en.cppreference.com/w/cpp/memory/unique_ptr/get), [`std::shared_ptr::get`](https://en.cppreference.com/w/cpp/memory/shared_ptr/get) and the [borrowing mechanism in Rust](https://doc.rust-lang.org/rust-by-example/scope/borrow.html). 14 | 15 | ## Example 16 | 17 | ```cpp 18 | #include 19 | 20 | #include 21 | 22 | struct RttiAware : pro::facade_builder 23 | ::support 24 | ::support 25 | ::build {}; 26 | 27 | int main() { 28 | pro::proxy p = pro::make_proxy(123); 29 | pro::proxy_view pv = p; 30 | proxy_cast(*pv) = 456; // Modifies the contained object of p 31 | std::cout << proxy_cast(*pv) << "\n"; // Prints "456" 32 | std::cout << proxy_cast(*p) << "\n"; // Prints "456" 33 | } 34 | ``` 35 | 36 | ## See Also 37 | 38 | - [`add_convention`](add_convention.md) 39 | -------------------------------------------------------------------------------- /docs/basic_facade_builder/support_weak.md: -------------------------------------------------------------------------------- 1 | # `basic_facade_builder::support_weak` 2 | 3 | ```cpp 4 | using support_weak = basic_facade_builder; 5 | ``` 6 | 7 | The member type `support_weak` of `basic_facade_builder` adds necessary convention types to allow implicit conversion from [`proxy`](../proxy.md)`` to [`weak_proxy`](../weak_proxy.md)`` where `F` is a [facade](../facade.md) type built from `basic_facade_builder`. 8 | 9 | Let `p` be a value of type `proxy`, `ptr` of type `P` be the contained value of `p` (if any), the conversion from type `const proxy&` to type `weak_proxy` is equivalent to `return typename P::weak_type{ptr}` if `p` contains a value, or otherwise equivalent to `return nullptr`. 10 | 11 | ## Notes 12 | 13 | `support_weak` is compatible with [`std::weak_ptr`](https://en.cppreference.com/w/cpp/memory/weak_ptr), and may generate more efficient code when working with [`make_proxy_shared`](../make_proxy_shared.md) or [`allocate_proxy_shared`](../allocate_proxy_shared.md). It is also compatible with any custom shared/weak ownership implementations if `typename P::weak_type{ptr}` is well-formed. 14 | 15 | ## Example 16 | 17 | ```cpp 18 | #include 19 | 20 | #include 21 | 22 | struct Formattable : pro::facade_builder 23 | ::support 24 | ::support 25 | ::build {}; 26 | 27 | int main() { 28 | pro::proxy p1 = pro::make_proxy_shared(123); 29 | pro::weak_proxy wp = p1; 30 | pro::proxy p2 = wp.lock(); 31 | std::cout << std::boolalpha << p2.has_value() << "\n"; // Prints "true" 32 | std::cout << std::format("{}\n", *p2); // Prints "123" 33 | 34 | p1.reset(); 35 | p2.reset(); 36 | p2 = wp.lock(); 37 | std::cout << p2.has_value() << "\n"; // Prints "false" 38 | } 39 | ``` 40 | 41 | ## See Also 42 | 43 | - [`add_convention`](add_convention.md) 44 | -------------------------------------------------------------------------------- /docs/constraint_level.md: -------------------------------------------------------------------------------- 1 | # Enum class `constraint_level` 2 | 3 | ```cpp 4 | enum class constraint_level : /* unspecified */ { 5 | none, nontrivial, nothrow, trivial 6 | }; 7 | ``` 8 | 9 | `constraint_level` defines the constraints on a type's lifetime operations (construction, relocation, or destruction). For a given operation `O`: 10 | 11 | - `none`: No restrictions on `O`. 12 | - `nontrivial`: `O` shall be supported. 13 | - `nothrow`: `O` shall be supported and shall not throw. 14 | - `trivial`: `O` shall be supported and shall be trivial. 15 | 16 | The specific semantics of each value depends on its context. 17 | 18 | ## See Also 19 | 20 | - [class `proxiable_ptr_constraints`](proxiable_ptr_constraints.md) 21 | -------------------------------------------------------------------------------- /docs/cpp20_modules_support.md: -------------------------------------------------------------------------------- 1 | # C++20 Modules support 2 | 3 | The "Proxy" library ships with `.ixx` files starting with version **4.0.0**. Compared to traditional headers, modules offer faster compilation speed and isolation against preprocessor macro definitions. 4 | 5 | As of 2025-05-11, CMake lacks support for forward compatibility when consuming C++ modules, which causes consumers with newer C++ standard to be unable to use modules with older standard. Until this is implemented by CMake, a CMake target containing the module can be manually declared using the following CMake script: 6 | 7 | ```cmake 8 | find_package(proxy REQUIRED) 9 | 10 | if(NOT DEFINED proxy_INCLUDE_DIR) # (1) 11 | if(NOT DEFINED proxy_SOURCE_DIR) 12 | message(FATAL_ERROR "proxy_INCLUDE_DIR or proxy_SOURCE_DIR must be defined to use this script.") 13 | endif() 14 | set(proxy_INCLUDE_DIR ${proxy_SOURCE_DIR}/include) 15 | endif() 16 | 17 | message(STATUS "Declaring `msft_proxy::module` target for include path ${proxy_INCLUDE_DIR}") 18 | 19 | add_library(msft_proxy_module) 20 | set_target_properties( 21 | msft_proxy_module 22 | PROPERTIES 23 | SYSTEM TRUE 24 | EXCLUDE_FROM_ALL TRUE 25 | ) 26 | 27 | add_library(msft_proxy::module ALIAS msft_proxy_module) 28 | target_sources(msft_proxy_module PUBLIC 29 | FILE_SET CXX_MODULES 30 | BASE_DIRS ${proxy_INCLUDE_DIR} 31 | FILES 32 | ${proxy_INCLUDE_DIR}/proxy/proxy.ixx 33 | ) 34 | target_compile_features(msft_proxy_module PUBLIC cxx_std_20) # (2) 35 | target_link_libraries(msft_proxy_module PUBLIC msft_proxy) 36 | ``` 37 | 38 | - (1) `proxy_INCLUDE_DIR` is automatically declared after `find_package(proxy)`. CPM uses a slightly different convention where `proxy_SOURCE_DIR` is declared after `CPMAddPackage`. 39 | - (2) The C++ standard version for `msft_proxy_module` target should be the same or higher than the consumer CMake target. For example if your project is using C++23 mode, this line should be changed to `cxx_std_23` or `cxx_std_26` / newer standards. 40 | 41 | It can then be consumed like this: 42 | 43 | ```cmake 44 | target_link_libraries(main PRIVATE msft_proxy::module) 45 | ``` 46 | 47 | ## Example 48 | 49 | Module definition: 50 | 51 | ```cpp 52 | // dictionary.cpp 53 | module; 54 | 55 | #include // (1) 56 | 57 | #include // (2) 58 | 59 | export module dictionary; 60 | 61 | import proxy; // (3) 62 | 63 | extern "C++" { // (4) 64 | PRO_DEF_MEM_DISPATCH(MemAt, at); 65 | } 66 | 67 | export struct Dictionary : pro::facade_builder 68 | ::add_convention 69 | ::build {}; 70 | 71 | ``` 72 | 73 | Client: 74 | 75 | ```cpp 76 | // main.cpp 77 | #include 78 | #include 79 | 80 | import proxy; 81 | import dictionary; 82 | 83 | int main() { 84 | std::vector v{"hello", "world"}; 85 | pro::proxy p = &v; 86 | std::cout << p->at(1) << "\n"; // Prints "world" 87 | } 88 | 89 | ``` 90 | 91 | - (1) This is a traditional header rather than a module. It should be declared in global fragment (after `module` and before `export module`). 92 | - (2) This makes all `PRO_DEF_` macros available. This header file contains only some macros and are therefore very fast to compile. 93 | - (3) `import proxy;` makes all public interfaces from `pro` namespace available in the current translation unit. 94 | - (4) As of 2025-05-11, clangd requires the accessor struct to be either `export`-ed, or be declared within an `extern "C++"` block, in order to have auto completion working. 95 | 96 | -------------------------------------------------------------------------------- /docs/explicit_conversion_dispatch.md: -------------------------------------------------------------------------------- 1 | # Class `explicit_conversion_dispatch` 2 | 3 | ```cpp 4 | class explicit_conversion_dispatch; // since 3.2.0 5 | 6 | using conversion_dispatch = explicit_conversion_dispatch; // since 3.2.0 7 | ``` 8 | 9 | Class `explicit_conversion_dispatch` models a [dispatch](ProDispatch.md) type for explicit type conversion expressions. It meets the [*ProAccessible* requirements](ProAccessible.md) of applicable types. `conversion_dispatch` is an alias of `explicit_conversion_dispatch`. 10 | 11 | ## Member Functions 12 | 13 | | Name | Description | 14 | | ------------------------------------------------------------ | --------------------------------------------------- | 15 | | (constructor) [nothrow] | constructs an `explicit_conversion_dispatch` object | 16 | | [`operator()`](explicit_conversion_dispatch/operator_call.md) | invokes the dispatch | 17 | 18 | ## Member Types 19 | 20 | | Name | Description | 21 | | ------------------------------------------------------ | --------------------------------- | 22 | | [`accessor`](explicit_conversion_dispatch/accessor.md) | provides accessibility to `proxy` | 23 | 24 | ## Example 25 | 26 | ```cpp 27 | #include 28 | 29 | #include 30 | 31 | struct IntConvertible : pro::facade_builder 32 | ::add_convention 33 | ::build {}; 34 | 35 | int main() { 36 | pro::proxy p = pro::make_proxy(123); // p holds a short 37 | std::cout << static_cast(*p) << "\n"; // Prints "123" 38 | } 39 | ``` 40 | 41 | ## See Also 42 | 43 | - [class `implicit_conversion_dispatch`](implicit_conversion_dispatch.md) 44 | - [class template `operator_dispatch`](operator_dispatch.md) 45 | -------------------------------------------------------------------------------- /docs/explicit_conversion_dispatch/accessor.md: -------------------------------------------------------------------------------- 1 | # Class template `explicit_conversion_dispatch::accessor` 2 | 3 | ```cpp 4 | // (1) 5 | template 6 | struct accessor { 7 | accessor() = delete; 8 | }; 9 | 10 | // (2) 11 | template 12 | requires(sizeof...(Os) > 1u && (std::is_constructible_v> && ...)) 13 | struct accessor : accessor... { 14 | using accessor::operator return-type-of...; 15 | }; 16 | 17 | // (3) 18 | template 19 | struct accessor { 20 | explicit operator T() cv ref noex; 21 | }; 22 | ``` 23 | 24 | `(1)` The default implementation of `accessor` is not constructible. 25 | 26 | `(2)` When `sizeof...(Os)` is greater than `1`, and `accessor...` are default-constructible, inherits all `accessor...` types and `using` their `operator return-type-of`. `return-type-of` denotes the *return type* of the overload type `O`. 27 | 28 | `(3)` When `sizeof...(Os)` is `1` and the only type `O` in `Os` is `T() cv ref noex`, provides an explicit `operator T()` with the same *cv ref noex* specifiers. `accessor::operator T()` is equivalent to `return proxy_invoke(access_proxy(std::forward(*this)))`. 29 | -------------------------------------------------------------------------------- /docs/explicit_conversion_dispatch/operator_call.md: -------------------------------------------------------------------------------- 1 | # `explicit_conversion_dispatch::operator()` 2 | 3 | ```cpp 4 | template 5 | /* see below */ operator()(T&& value) const noexcept; 6 | ``` 7 | 8 | Returns a value that is implicitly convertible to any type `U` with expression `U{std::forward(value)}` when `T` is explicitly convertible to type `U`. 9 | -------------------------------------------------------------------------------- /docs/facade.md: -------------------------------------------------------------------------------- 1 | # Concept `facade` 2 | 3 | ```cpp 4 | template 5 | concept facade = /* see-below */; 6 | ``` 7 | 8 | The concept `facade` specifies that a type `F` models a facade of [`proxy`](proxy.md). If `F` depends on an incomplete type, and its evaluation could yield a different result if that type were hypothetically completed, the behavior is undefined. `facade` is `true` when `F` meets the [*ProBasicFacade* requirements](ProBasicFacade.md); otherwise, it is `false`. 9 | 10 | Note that concept `facade` does not impose strong constraints on the dependent convention and reflection types. It is recommended to use [`facade_builder`](basic_facade_builder.md) to define a facade type that models concept `facade`. 11 | 12 | ## See Also 13 | 14 | - [class template `basic_facade_builder`](basic_facade_builder.md) 15 | - [concept `proxiable`](proxiable.md) 16 | - [function template `make_proxy`](make_proxy.md) 17 | -------------------------------------------------------------------------------- /docs/facade_aware_overload_t.md: -------------------------------------------------------------------------------- 1 | # Class template `facade_aware_overload_t` 2 | 3 | ```cpp 4 | template