Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C++ (Circle)
CIRCT
Clean
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
GLSL
Go
Haskell
HLSL
Hook
Hylo
IL
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Nim
Objective-C
Objective-C++
OCaml
OpenCL C
Pascal
Pony
Python
Racket
Ruby
Rust
Snowball
Scala
Solidity
Spice
SPIR-V
Swift
LLVM TableGen
Toit
TypeScript Native
V
Vala
Visual Basic
WASM
Zig
Javascript
GIMPLE
Ygen
c++ source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
6502-c++ 11.1.0
ARM GCC 10.2.0
ARM GCC 10.3.0
ARM GCC 10.4.0
ARM GCC 10.5.0
ARM GCC 11.1.0
ARM GCC 11.2.0
ARM GCC 11.3.0
ARM GCC 11.4.0
ARM GCC 12.1.0
ARM GCC 12.2.0
ARM GCC 12.3.0
ARM GCC 12.4.0
ARM GCC 13.1.0
ARM GCC 13.2.0
ARM GCC 13.2.0 (unknown-eabi)
ARM GCC 13.3.0
ARM GCC 13.3.0 (unknown-eabi)
ARM GCC 14.1.0
ARM GCC 14.1.0 (unknown-eabi)
ARM GCC 14.2.0
ARM GCC 14.2.0 (unknown-eabi)
ARM GCC 4.5.4
ARM GCC 4.6.4
ARM GCC 5.4
ARM GCC 6.3.0
ARM GCC 6.4.0
ARM GCC 7.3.0
ARM GCC 7.5.0
ARM GCC 8.2.0
ARM GCC 8.5.0
ARM GCC 9.3.0
ARM GCC 9.4.0
ARM GCC 9.5.0
ARM GCC trunk
ARM gcc 10.2.1 (none)
ARM gcc 10.3.1 (2021.07 none)
ARM gcc 10.3.1 (2021.10 none)
ARM gcc 11.2.1 (none)
ARM gcc 5.4.1 (none)
ARM gcc 7.2.1 (none)
ARM gcc 8.2 (WinCE)
ARM gcc 8.3.1 (none)
ARM gcc 9.2.1 (none)
ARM msvc v19.0 (WINE)
ARM msvc v19.10 (WINE)
ARM msvc v19.14 (WINE)
ARM64 Morello gcc 10.1 Alpha 2
ARM64 gcc 10.2
ARM64 gcc 10.3
ARM64 gcc 10.4
ARM64 gcc 10.5.0
ARM64 gcc 11.1
ARM64 gcc 11.2
ARM64 gcc 11.3
ARM64 gcc 11.4.0
ARM64 gcc 12.1
ARM64 gcc 12.2.0
ARM64 gcc 12.3.0
ARM64 gcc 12.4.0
ARM64 gcc 13.1.0
ARM64 gcc 13.2.0
ARM64 gcc 13.3.0
ARM64 gcc 14.1.0
ARM64 gcc 14.2.0
ARM64 gcc 4.9.4
ARM64 gcc 5.4
ARM64 gcc 5.5.0
ARM64 gcc 6.3
ARM64 gcc 6.4
ARM64 gcc 7.3
ARM64 gcc 7.5
ARM64 gcc 8.2
ARM64 gcc 8.5
ARM64 gcc 9.3
ARM64 gcc 9.4
ARM64 gcc 9.5
ARM64 gcc trunk
ARM64 msvc v19.14 (WINE)
AVR gcc 10.3.0
AVR gcc 11.1.0
AVR gcc 12.1.0
AVR gcc 12.2.0
AVR gcc 12.3.0
AVR gcc 12.4.0
AVR gcc 13.1.0
AVR gcc 13.2.0
AVR gcc 13.3.0
AVR gcc 14.1.0
AVR gcc 14.2.0
AVR gcc 4.5.4
AVR gcc 4.6.4
AVR gcc 5.4.0
AVR gcc 9.2.0
AVR gcc 9.3.0
Arduino Mega (1.8.9)
Arduino Uno (1.8.9)
BPF clang (trunk)
BPF clang 13.0.0
BPF clang 14.0.0
BPF clang 15.0.0
BPF clang 16.0.0
BPF clang 17.0.1
BPF clang 18.1.0
BPF clang 19.1.0
BPF gcc 13.1.0
BPF gcc 13.2.0
BPF gcc 13.3.0
BPF gcc trunk
EDG (experimental reflection)
EDG 6.5
EDG 6.5 (GNU mode gcc 13)
EDG 6.6
EDG 6.6 (GNU mode gcc 13)
FRC 2019
FRC 2020
FRC 2023
HPPA gcc 14.2.0
KVX ACB 4.1.0 (GCC 7.5.0)
KVX ACB 4.1.0-cd1 (GCC 7.5.0)
KVX ACB 4.10.0 (GCC 10.3.1)
KVX ACB 4.11.1 (GCC 10.3.1)
KVX ACB 4.12.0 (GCC 11.3.0)
KVX ACB 4.2.0 (GCC 7.5.0)
KVX ACB 4.3.0 (GCC 7.5.0)
KVX ACB 4.4.0 (GCC 7.5.0)
KVX ACB 4.6.0 (GCC 9.4.1)
KVX ACB 4.8.0 (GCC 9.4.1)
KVX ACB 4.9.0 (GCC 9.4.1)
KVX ACB 5.0.0 (GCC 12.2.1)
KVX ACB 5.2.0 (GCC 13.2.1)
LoongArch64 clang (trunk)
LoongArch64 clang 17.0.1
LoongArch64 clang 18.1.0
LoongArch64 clang 19.1.0
M68K gcc 13.1.0
M68K gcc 13.2.0
M68K gcc 13.3.0
M68K gcc 14.1.0
M68K gcc 14.2.0
M68k clang (trunk)
MRISC32 gcc (trunk)
MSP430 gcc 4.5.3
MSP430 gcc 5.3.0
MSP430 gcc 6.2.1
MinGW clang 14.0.3
MinGW clang 14.0.6
MinGW clang 15.0.7
MinGW clang 16.0.0
MinGW clang 16.0.2
MinGW gcc 11.3.0
MinGW gcc 12.1.0
MinGW gcc 12.2.0
MinGW gcc 13.1.0
RISC-V (32-bits) gcc (trunk)
RISC-V (32-bits) gcc 10.2.0
RISC-V (32-bits) gcc 10.3.0
RISC-V (32-bits) gcc 11.2.0
RISC-V (32-bits) gcc 11.3.0
RISC-V (32-bits) gcc 11.4.0
RISC-V (32-bits) gcc 12.1.0
RISC-V (32-bits) gcc 12.2.0
RISC-V (32-bits) gcc 12.3.0
RISC-V (32-bits) gcc 12.4.0
RISC-V (32-bits) gcc 13.1.0
RISC-V (32-bits) gcc 13.2.0
RISC-V (32-bits) gcc 13.3.0
RISC-V (32-bits) gcc 14.1.0
RISC-V (32-bits) gcc 14.2.0
RISC-V (32-bits) gcc 8.2.0
RISC-V (32-bits) gcc 8.5.0
RISC-V (32-bits) gcc 9.4.0
RISC-V (64-bits) gcc (trunk)
RISC-V (64-bits) gcc 10.2.0
RISC-V (64-bits) gcc 10.3.0
RISC-V (64-bits) gcc 11.2.0
RISC-V (64-bits) gcc 11.3.0
RISC-V (64-bits) gcc 11.4.0
RISC-V (64-bits) gcc 12.1.0
RISC-V (64-bits) gcc 12.2.0
RISC-V (64-bits) gcc 12.3.0
RISC-V (64-bits) gcc 12.4.0
RISC-V (64-bits) gcc 13.1.0
RISC-V (64-bits) gcc 13.2.0
RISC-V (64-bits) gcc 13.3.0
RISC-V (64-bits) gcc 14.1.0
RISC-V (64-bits) gcc 14.2.0
RISC-V (64-bits) gcc 8.2.0
RISC-V (64-bits) gcc 8.5.0
RISC-V (64-bits) gcc 9.4.0
RISC-V rv32gc clang (trunk)
RISC-V rv32gc clang 10.0.0
RISC-V rv32gc clang 10.0.1
RISC-V rv32gc clang 11.0.0
RISC-V rv32gc clang 11.0.1
RISC-V rv32gc clang 12.0.0
RISC-V rv32gc clang 12.0.1
RISC-V rv32gc clang 13.0.0
RISC-V rv32gc clang 13.0.1
RISC-V rv32gc clang 14.0.0
RISC-V rv32gc clang 15.0.0
RISC-V rv32gc clang 16.0.0
RISC-V rv32gc clang 17.0.1
RISC-V rv32gc clang 18.1.0
RISC-V rv32gc clang 19.1.0
RISC-V rv32gc clang 9.0.0
RISC-V rv32gc clang 9.0.1
RISC-V rv64gc clang (trunk)
RISC-V rv64gc clang 10.0.0
RISC-V rv64gc clang 10.0.1
RISC-V rv64gc clang 11.0.0
RISC-V rv64gc clang 11.0.1
RISC-V rv64gc clang 12.0.0
RISC-V rv64gc clang 12.0.1
RISC-V rv64gc clang 13.0.0
RISC-V rv64gc clang 13.0.1
RISC-V rv64gc clang 14.0.0
RISC-V rv64gc clang 15.0.0
RISC-V rv64gc clang 16.0.0
RISC-V rv64gc clang 17.0.1
RISC-V rv64gc clang 18.1.0
RISC-V rv64gc clang 19.1.0
RISC-V rv64gc clang 9.0.0
RISC-V rv64gc clang 9.0.1
Raspbian Buster
Raspbian Stretch
SPARC LEON gcc 12.2.0
SPARC LEON gcc 12.3.0
SPARC LEON gcc 12.4.0
SPARC LEON gcc 13.1.0
SPARC LEON gcc 13.2.0
SPARC LEON gcc 13.3.0
SPARC LEON gcc 14.1.0
SPARC LEON gcc 14.2.0
SPARC gcc 12.2.0
SPARC gcc 12.3.0
SPARC gcc 12.4.0
SPARC gcc 13.1.0
SPARC gcc 13.2.0
SPARC gcc 13.3.0
SPARC gcc 14.1.0
SPARC gcc 14.2.0
SPARC64 gcc 12.2.0
SPARC64 gcc 12.3.0
SPARC64 gcc 12.4.0
SPARC64 gcc 13.1.0
SPARC64 gcc 13.2.0
SPARC64 gcc 13.3.0
SPARC64 gcc 14.1.0
SPARC64 gcc 14.2.0
TI C6x gcc 12.2.0
TI C6x gcc 12.3.0
TI C6x gcc 12.4.0
TI C6x gcc 13.1.0
TI C6x gcc 13.2.0
TI C6x gcc 13.3.0
TI C6x gcc 14.1.0
TI C6x gcc 14.2.0
TI CL430 21.6.1
VAX gcc NetBSDELF 10.4.0
VAX gcc NetBSDELF 10.5.0 (Nov 15 03:50:22 2023)
WebAssembly clang (trunk)
Xtensa ESP32 gcc 11.2.0 (2022r1)
Xtensa ESP32 gcc 12.2.0 (20230208)
Xtensa ESP32 gcc 8.2.0 (2019r2)
Xtensa ESP32 gcc 8.2.0 (2020r1)
Xtensa ESP32 gcc 8.2.0 (2020r2)
Xtensa ESP32 gcc 8.4.0 (2020r3)
Xtensa ESP32 gcc 8.4.0 (2021r1)
Xtensa ESP32 gcc 8.4.0 (2021r2)
Xtensa ESP32-S2 gcc 11.2.0 (2022r1)
Xtensa ESP32-S2 gcc 12.2.0 (20230208)
Xtensa ESP32-S2 gcc 8.2.0 (2019r2)
Xtensa ESP32-S2 gcc 8.2.0 (2020r1)
Xtensa ESP32-S2 gcc 8.2.0 (2020r2)
Xtensa ESP32-S2 gcc 8.4.0 (2020r3)
Xtensa ESP32-S2 gcc 8.4.0 (2021r1)
Xtensa ESP32-S2 gcc 8.4.0 (2021r2)
Xtensa ESP32-S3 gcc 11.2.0 (2022r1)
Xtensa ESP32-S3 gcc 12.2.0 (20230208)
Xtensa ESP32-S3 gcc 8.4.0 (2020r3)
Xtensa ESP32-S3 gcc 8.4.0 (2021r1)
Xtensa ESP32-S3 gcc 8.4.0 (2021r2)
arm64 msvc v19.20 VS16.0
arm64 msvc v19.21 VS16.1
arm64 msvc v19.22 VS16.2
arm64 msvc v19.23 VS16.3
arm64 msvc v19.24 VS16.4
arm64 msvc v19.25 VS16.5
arm64 msvc v19.27 VS16.7
arm64 msvc v19.28 VS16.8
arm64 msvc v19.28 VS16.9
arm64 msvc v19.29 VS16.10
arm64 msvc v19.29 VS16.11
arm64 msvc v19.30 VS17.0
arm64 msvc v19.31 VS17.1
arm64 msvc v19.32 VS17.2
arm64 msvc v19.33 VS17.3
arm64 msvc v19.34 VS17.4
arm64 msvc v19.35 VS17.5
arm64 msvc v19.36 VS17.6
arm64 msvc v19.37 VS17.7
arm64 msvc v19.38 VS17.8
arm64 msvc v19.39 VS17.9
arm64 msvc v19.40 VS17.10
arm64 msvc v19.latest
armv7-a clang (trunk)
armv7-a clang 10.0.0
armv7-a clang 10.0.1
armv7-a clang 11.0.0
armv7-a clang 11.0.1
armv7-a clang 12.0.0
armv7-a clang 12.0.1
armv7-a clang 13.0.0
armv7-a clang 13.0.1
armv7-a clang 14.0.0
armv7-a clang 15.0.0
armv7-a clang 16.0.0
armv7-a clang 17.0.1
armv7-a clang 18.1.0
armv7-a clang 19.1.0
armv7-a clang 9.0.0
armv7-a clang 9.0.1
armv8-a clang (all architectural features, trunk)
armv8-a clang (trunk)
armv8-a clang 10.0.0
armv8-a clang 10.0.1
armv8-a clang 11.0.0
armv8-a clang 11.0.1
armv8-a clang 12.0.0
armv8-a clang 13.0.0
armv8-a clang 14.0.0
armv8-a clang 15.0.0
armv8-a clang 16.0.0
armv8-a clang 17.0.1
armv8-a clang 18.1.0
armv8-a clang 19.1.0
armv8-a clang 9.0.0
armv8-a clang 9.0.1
clang-cl 18.1.0
ellcc 0.1.33
ellcc 0.1.34
ellcc 2017-07-16
hexagon-clang 16.0.5
llvm-mos atari2600-3e
llvm-mos atari2600-4k
llvm-mos atari2600-common
llvm-mos atari5200-supercart
llvm-mos atari8-cart-megacart
llvm-mos atari8-cart-std
llvm-mos atari8-cart-xegs
llvm-mos atari8-common
llvm-mos atari8-dos
llvm-mos c128
llvm-mos c64
llvm-mos commodore
llvm-mos cpm65
llvm-mos cx16
llvm-mos dodo
llvm-mos eater
llvm-mos mega65
llvm-mos nes
llvm-mos nes-action53
llvm-mos nes-cnrom
llvm-mos nes-gtrom
llvm-mos nes-mmc1
llvm-mos nes-mmc3
llvm-mos nes-nrom
llvm-mos nes-unrom
llvm-mos nes-unrom-512
llvm-mos osi-c1p
llvm-mos pce
llvm-mos pce-cd
llvm-mos pce-common
llvm-mos pet
llvm-mos rp6502
llvm-mos rpc8e
llvm-mos supervision
llvm-mos vic20
loongarch64 gcc 12.2.0
loongarch64 gcc 12.3.0
loongarch64 gcc 12.4.0
loongarch64 gcc 13.1.0
loongarch64 gcc 13.2.0
loongarch64 gcc 13.3.0
loongarch64 gcc 14.1.0
loongarch64 gcc 14.2.0
mips clang 13.0.0
mips clang 14.0.0
mips clang 15.0.0
mips clang 16.0.0
mips clang 17.0.1
mips clang 18.1.0
mips clang 19.1.0
mips gcc 11.2.0
mips gcc 12.1.0
mips gcc 12.2.0
mips gcc 12.3.0
mips gcc 12.4.0
mips gcc 13.1.0
mips gcc 13.2.0
mips gcc 13.3.0
mips gcc 14.1.0
mips gcc 14.2.0
mips gcc 4.9.4
mips gcc 5.4
mips gcc 5.5.0
mips gcc 9.3.0 (codescape)
mips gcc 9.5.0
mips64 (el) gcc 12.1.0
mips64 (el) gcc 12.2.0
mips64 (el) gcc 12.3.0
mips64 (el) gcc 12.4.0
mips64 (el) gcc 13.1.0
mips64 (el) gcc 13.2.0
mips64 (el) gcc 13.3.0
mips64 (el) gcc 14.1.0
mips64 (el) gcc 14.2.0
mips64 (el) gcc 4.9.4
mips64 (el) gcc 5.4.0
mips64 (el) gcc 5.5.0
mips64 (el) gcc 9.5.0
mips64 clang 13.0.0
mips64 clang 14.0.0
mips64 clang 15.0.0
mips64 clang 16.0.0
mips64 clang 17.0.1
mips64 clang 18.1.0
mips64 clang 19.1.0
mips64 gcc 11.2.0
mips64 gcc 12.1.0
mips64 gcc 12.2.0
mips64 gcc 12.3.0
mips64 gcc 12.4.0
mips64 gcc 13.1.0
mips64 gcc 13.2.0
mips64 gcc 13.3.0
mips64 gcc 14.1.0
mips64 gcc 14.2.0
mips64 gcc 4.9.4
mips64 gcc 5.4.0
mips64 gcc 5.5.0
mips64 gcc 9.5.0
mips64el clang 13.0.0
mips64el clang 14.0.0
mips64el clang 15.0.0
mips64el clang 16.0.0
mips64el clang 17.0.1
mips64el clang 18.1.0
mips64el clang 19.1.0
mipsel clang 13.0.0
mipsel clang 14.0.0
mipsel clang 15.0.0
mipsel clang 16.0.0
mipsel clang 17.0.1
mipsel clang 18.1.0
mipsel clang 19.1.0
mipsel gcc 12.1.0
mipsel gcc 12.2.0
mipsel gcc 12.3.0
mipsel gcc 12.4.0
mipsel gcc 13.1.0
mipsel gcc 13.2.0
mipsel gcc 13.3.0
mipsel gcc 14.1.0
mipsel gcc 14.2.0
mipsel gcc 4.9.4
mipsel gcc 5.4.0
mipsel gcc 5.5.0
mipsel gcc 9.5.0
nanoMIPS gcc 6.3.0 (mtk)
power gcc 11.2.0
power gcc 12.1.0
power gcc 12.2.0
power gcc 12.3.0
power gcc 12.4.0
power gcc 13.1.0
power gcc 13.2.0
power gcc 13.3.0
power gcc 14.1.0
power gcc 14.2.0
power gcc 4.8.5
power64 AT12.0 (gcc8)
power64 AT13.0 (gcc9)
power64 gcc 11.2.0
power64 gcc 12.1.0
power64 gcc 12.2.0
power64 gcc 12.3.0
power64 gcc 12.4.0
power64 gcc 13.1.0
power64 gcc 13.2.0
power64 gcc 13.3.0
power64 gcc 14.1.0
power64 gcc 14.2.0
power64 gcc trunk
power64le AT12.0 (gcc8)
power64le AT13.0 (gcc9)
power64le clang (trunk)
power64le gcc 11.2.0
power64le gcc 12.1.0
power64le gcc 12.2.0
power64le gcc 12.3.0
power64le gcc 12.4.0
power64le gcc 13.1.0
power64le gcc 13.2.0
power64le gcc 13.3.0
power64le gcc 14.1.0
power64le gcc 14.2.0
power64le gcc 6.3.0
power64le gcc trunk
powerpc64 clang (trunk)
s390x gcc 11.2.0
s390x gcc 12.1.0
s390x gcc 12.2.0
s390x gcc 12.3.0
s390x gcc 12.4.0
s390x gcc 13.1.0
s390x gcc 13.2.0
s390x gcc 13.3.0
s390x gcc 14.1.0
s390x gcc 14.2.0
sh gcc 12.2.0
sh gcc 12.3.0
sh gcc 12.4.0
sh gcc 13.1.0
sh gcc 13.2.0
sh gcc 13.3.0
sh gcc 14.1.0
sh gcc 14.2.0
sh gcc 4.9.4
sh gcc 9.5.0
vast (trunk)
x64 msvc v19.0 (WINE)
x64 msvc v19.10 (WINE)
x64 msvc v19.14 (WINE)
x64 msvc v19.20 VS16.0
x64 msvc v19.21 VS16.1
x64 msvc v19.22 VS16.2
x64 msvc v19.23 VS16.3
x64 msvc v19.24 VS16.4
x64 msvc v19.25 VS16.5
x64 msvc v19.27 VS16.7
x64 msvc v19.28 VS16.8
x64 msvc v19.28 VS16.9
x64 msvc v19.29 VS16.10
x64 msvc v19.29 VS16.11
x64 msvc v19.30 VS17.0
x64 msvc v19.31 VS17.1
x64 msvc v19.32 VS17.2
x64 msvc v19.33 VS17.3
x64 msvc v19.34 VS17.4
x64 msvc v19.35 VS17.5
x64 msvc v19.36 VS17.6
x64 msvc v19.37 VS17.7
x64 msvc v19.38 VS17.8
x64 msvc v19.39 VS17.9
x64 msvc v19.40 VS17.10
x64 msvc v19.latest
x86 djgpp 4.9.4
x86 djgpp 5.5.0
x86 djgpp 6.4.0
x86 djgpp 7.2.0
x86 msvc v19.0 (WINE)
x86 msvc v19.10 (WINE)
x86 msvc v19.14 (WINE)
x86 msvc v19.20 VS16.0
x86 msvc v19.21 VS16.1
x86 msvc v19.22 VS16.2
x86 msvc v19.23 VS16.3
x86 msvc v19.24 VS16.4
x86 msvc v19.25 VS16.5
x86 msvc v19.27 VS16.7
x86 msvc v19.28 VS16.8
x86 msvc v19.28 VS16.9
x86 msvc v19.29 VS16.10
x86 msvc v19.29 VS16.11
x86 msvc v19.30 VS17.0
x86 msvc v19.31 VS17.1
x86 msvc v19.32 VS17.2
x86 msvc v19.33 VS17.3
x86 msvc v19.34 VS17.4
x86 msvc v19.35 VS17.5
x86 msvc v19.36 VS17.6
x86 msvc v19.37 VS17.7
x86 msvc v19.38 VS17.8
x86 msvc v19.39 VS17.9
x86 msvc v19.40 VS17.10
x86 msvc v19.latest
x86 nvc++ 22.11
x86 nvc++ 22.7
x86 nvc++ 22.9
x86 nvc++ 23.1
x86 nvc++ 23.11
x86 nvc++ 23.3
x86 nvc++ 23.5
x86 nvc++ 23.7
x86 nvc++ 23.9
x86 nvc++ 24.1
x86 nvc++ 24.3
x86 nvc++ 24.5
x86 nvc++ 24.7
x86 nvc++ 24.9
x86-64 Zapcc 190308
x86-64 clang (EricWF contracts)
x86-64 clang (amd-staging)
x86-64 clang (assertions trunk)
x86-64 clang (clangir)
x86-64 clang (dascandy contracts)
x86-64 clang (experimental -Wlifetime)
x86-64 clang (experimental P1061)
x86-64 clang (experimental P1144)
x86-64 clang (experimental P1221)
x86-64 clang (experimental P2996)
x86-64 clang (experimental P3068)
x86-64 clang (experimental P3309)
x86-64 clang (experimental P3367)
x86-64 clang (experimental P3372)
x86-64 clang (experimental metaprogramming - P2632)
x86-64 clang (old concepts branch)
x86-64 clang (p1974)
x86-64 clang (pattern matching - P2688)
x86-64 clang (reflection)
x86-64 clang (resugar)
x86-64 clang (string interpolation - P3412)
x86-64 clang (thephd.dev)
x86-64 clang (trunk)
x86-64 clang (variadic friends - P2893)
x86-64 clang (widberg)
x86-64 clang 10.0.0
x86-64 clang 10.0.0 (assertions)
x86-64 clang 10.0.1
x86-64 clang 11.0.0
x86-64 clang 11.0.0 (assertions)
x86-64 clang 11.0.1
x86-64 clang 12.0.0
x86-64 clang 12.0.0 (assertions)
x86-64 clang 12.0.1
x86-64 clang 13.0.0
x86-64 clang 13.0.0 (assertions)
x86-64 clang 13.0.1
x86-64 clang 14.0.0
x86-64 clang 14.0.0 (assertions)
x86-64 clang 15.0.0
x86-64 clang 15.0.0 (assertions)
x86-64 clang 16.0.0
x86-64 clang 16.0.0 (assertions)
x86-64 clang 17.0.1
x86-64 clang 17.0.1 (assertions)
x86-64 clang 18.1.0
x86-64 clang 18.1.0 (assertions)
x86-64 clang 19.1.0
x86-64 clang 19.1.0 (assertions)
x86-64 clang 2.6.0 (assertions)
x86-64 clang 2.7.0 (assertions)
x86-64 clang 2.8.0 (assertions)
x86-64 clang 2.9.0 (assertions)
x86-64 clang 3.0.0
x86-64 clang 3.0.0 (assertions)
x86-64 clang 3.1
x86-64 clang 3.1 (assertions)
x86-64 clang 3.2
x86-64 clang 3.2 (assertions)
x86-64 clang 3.3
x86-64 clang 3.3 (assertions)
x86-64 clang 3.4 (assertions)
x86-64 clang 3.4.1
x86-64 clang 3.5
x86-64 clang 3.5 (assertions)
x86-64 clang 3.5.1
x86-64 clang 3.5.2
x86-64 clang 3.6
x86-64 clang 3.6 (assertions)
x86-64 clang 3.7
x86-64 clang 3.7 (assertions)
x86-64 clang 3.7.1
x86-64 clang 3.8
x86-64 clang 3.8 (assertions)
x86-64 clang 3.8.1
x86-64 clang 3.9.0
x86-64 clang 3.9.0 (assertions)
x86-64 clang 3.9.1
x86-64 clang 4.0.0
x86-64 clang 4.0.0 (assertions)
x86-64 clang 4.0.1
x86-64 clang 5.0.0
x86-64 clang 5.0.0 (assertions)
x86-64 clang 5.0.1
x86-64 clang 5.0.2
x86-64 clang 6.0.0
x86-64 clang 6.0.0 (assertions)
x86-64 clang 6.0.1
x86-64 clang 7.0.0
x86-64 clang 7.0.0 (assertions)
x86-64 clang 7.0.1
x86-64 clang 7.1.0
x86-64 clang 8.0.0
x86-64 clang 8.0.0 (assertions)
x86-64 clang 8.0.1
x86-64 clang 9.0.0
x86-64 clang 9.0.0 (assertions)
x86-64 clang 9.0.1
x86-64 clang rocm-4.5.2
x86-64 clang rocm-5.0.2
x86-64 clang rocm-5.1.3
x86-64 clang rocm-5.2.3
x86-64 clang rocm-5.3.3
x86-64 clang rocm-5.7.0
x86-64 clang rocm-6.0.2
x86-64 clang rocm-6.1.2
x86-64 gcc (contract labels)
x86-64 gcc (contracts natural syntax)
x86-64 gcc (contracts)
x86-64 gcc (coroutines)
x86-64 gcc (modules)
x86-64 gcc (trunk)
x86-64 gcc 10.1
x86-64 gcc 10.2
x86-64 gcc 10.3
x86-64 gcc 10.4
x86-64 gcc 10.5
x86-64 gcc 11.1
x86-64 gcc 11.2
x86-64 gcc 11.3
x86-64 gcc 11.4
x86-64 gcc 12.1
x86-64 gcc 12.2
x86-64 gcc 12.3
x86-64 gcc 12.4
x86-64 gcc 13.1
x86-64 gcc 13.2
x86-64 gcc 13.3
x86-64 gcc 14.1
x86-64 gcc 14.2
x86-64 gcc 3.4.6
x86-64 gcc 4.0.4
x86-64 gcc 4.1.2
x86-64 gcc 4.4.7
x86-64 gcc 4.5.3
x86-64 gcc 4.6.4
x86-64 gcc 4.7.1
x86-64 gcc 4.7.2
x86-64 gcc 4.7.3
x86-64 gcc 4.7.4
x86-64 gcc 4.8.1
x86-64 gcc 4.8.2
x86-64 gcc 4.8.3
x86-64 gcc 4.8.4
x86-64 gcc 4.8.5
x86-64 gcc 4.9.0
x86-64 gcc 4.9.1
x86-64 gcc 4.9.2
x86-64 gcc 4.9.3
x86-64 gcc 4.9.4
x86-64 gcc 5.1
x86-64 gcc 5.2
x86-64 gcc 5.3
x86-64 gcc 5.4
x86-64 gcc 5.5
x86-64 gcc 6.1
x86-64 gcc 6.2
x86-64 gcc 6.3
x86-64 gcc 6.4
x86-64 gcc 6.5
x86-64 gcc 7.1
x86-64 gcc 7.2
x86-64 gcc 7.3
x86-64 gcc 7.4
x86-64 gcc 7.5
x86-64 gcc 8.1
x86-64 gcc 8.2
x86-64 gcc 8.3
x86-64 gcc 8.4
x86-64 gcc 8.5
x86-64 gcc 9.1
x86-64 gcc 9.2
x86-64 gcc 9.3
x86-64 gcc 9.4
x86-64 gcc 9.5
x86-64 icc 13.0.1
x86-64 icc 16.0.3
x86-64 icc 17.0.0
x86-64 icc 18.0.0
x86-64 icc 19.0.0
x86-64 icc 19.0.1
x86-64 icc 2021.1.2
x86-64 icc 2021.10.0
x86-64 icc 2021.2.0
x86-64 icc 2021.3.0
x86-64 icc 2021.4.0
x86-64 icc 2021.5.0
x86-64 icc 2021.6.0
x86-64 icc 2021.7.0
x86-64 icc 2021.7.1
x86-64 icc 2021.8.0
x86-64 icc 2021.9.0
x86-64 icx 2021.1.2
x86-64 icx 2021.2.0
x86-64 icx 2021.3.0
x86-64 icx 2021.4.0
x86-64 icx 2022.0.0
x86-64 icx 2022.1.0
x86-64 icx 2022.2.0
x86-64 icx 2022.2.1
x86-64 icx 2023.0.0
x86-64 icx 2023.1.0
x86-64 icx 2023.2.1
x86-64 icx 2024.0.0
x86-64 icx 2024.1.0
x86-64 icx 2024.2.0
x86-64 icx 2025.0.0
x86-64 icx 2025.0.0
zig c++ 0.10.0
zig c++ 0.11.0
zig c++ 0.12.0
zig c++ 0.12.1
zig c++ 0.13.0
zig c++ 0.6.0
zig c++ 0.7.0
zig c++ 0.7.1
zig c++ 0.8.0
zig c++ 0.9.0
zig c++ trunk
Options
Source code
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. #ifndef _MSFT_PROXY_ #define _MSFT_PROXY_ #include <cstddef> #include <bit> #include <concepts> #include <initializer_list> #include <limits> #include <memory> #include <tuple> #include <type_traits> #include <utility> #if __has_cpp_attribute(msvc::no_unique_address) #define ___PRO_NO_UNIQUE_ADDRESS_ATTRIBUTE msvc::no_unique_address #elif __has_cpp_attribute(no_unique_address) #define ___PRO_NO_UNIQUE_ADDRESS_ATTRIBUTE no_unique_address #else #error "Proxy requires C++20 attribute no_unique_address" #endif #if defined(_MSC_VER) && !defined(__clang__) #define ___PRO_ENFORCE_EBO __declspec(empty_bases) #else #define ___PRO_ENFORCE_EBO #endif // defined(_MSC_VER) && !defined(__clang__) #define __msft_lib_proxy 202408L namespace pro { enum class constraint_level { none, nontrivial, nothrow, trivial }; struct proxiable_ptr_constraints { std::size_t max_size; std::size_t max_align; constraint_level copyability; constraint_level relocatability; constraint_level destructibility; }; template <class F> class proxy; namespace details { struct applicable_traits { static constexpr bool applicable = true; }; struct inapplicable_traits { static constexpr bool applicable = false; }; enum class qualifier_type { lv, const_lv, rv, const_rv }; template <class T, qualifier_type Q> struct add_qualifier_traits; template <class T> struct add_qualifier_traits<T, qualifier_type::lv> : std::type_identity<T&> {}; template <class T> struct add_qualifier_traits<T, qualifier_type::const_lv> : std::type_identity<const T&> {}; template <class T> struct add_qualifier_traits<T, qualifier_type::rv> : std::type_identity<T&&> {}; template <class T> struct add_qualifier_traits<T, qualifier_type::const_rv> : std::type_identity<const T&&> {}; template <class T, qualifier_type Q> using add_qualifier_t = typename add_qualifier_traits<T, Q>::type; template <class T, qualifier_type Q> using add_qualifier_ptr_t = std::remove_reference_t<add_qualifier_t<T, Q>>*; template <template <class, class> class R, class O, class... Is> struct recursive_reduction : std::type_identity<O> {}; template <template <class, class> class R, class O, class... Is> using recursive_reduction_t = typename recursive_reduction<R, O, Is...>::type; template <template <class, class> class R, class O, class I, class... Is> struct recursive_reduction<R, O, I, Is...> { using type = recursive_reduction_t<R, R<O, I>, Is...>; }; template <class Expr> consteval bool is_consteval(Expr) { return requires { typename std::bool_constant<(Expr{}(), false)>; }; } template <class T, std::size_t I> concept has_tuple_element = requires { typename std::tuple_element_t<I, T>; }; template <class T> consteval bool is_tuple_like_well_formed() { if constexpr (requires { { std::tuple_size<T>::value } -> std::same_as<const std::size_t&>; }) { if constexpr (is_consteval([] { return std::tuple_size<T>::value; })) { return []<std::size_t... I>(std::index_sequence<I...>) { return (has_tuple_element<T, I> && ...); }(std::make_index_sequence<std::tuple_size_v<T>>{}); } } return false; } template <template <class...> class T, class TL, class Is, class... Args> struct instantiated_traits; template <template <class...> class T, class TL, std::size_t... Is, class... Args> struct instantiated_traits<T, TL, std::index_sequence<Is...>, Args...> { using type = T<Args..., std::tuple_element_t<Is, TL>...>; }; template <template <class...> class T, class TL, class... Args> using instantiated_t = typename instantiated_traits< T, TL, std::make_index_sequence<std::tuple_size_v<TL>>, Args...>::type; template <class T> consteval bool has_copyability(constraint_level level) { switch (level) { case constraint_level::none: return true; case constraint_level::nontrivial: return std::is_copy_constructible_v<T>; case constraint_level::nothrow: return std::is_nothrow_copy_constructible_v<T>; case constraint_level::trivial: return std::is_trivially_copy_constructible_v<T> && std::is_trivially_destructible_v<T>; default: return false; } } template <class T> consteval bool has_relocatability(constraint_level level) { switch (level) { case constraint_level::none: return true; case constraint_level::nontrivial: return std::is_move_constructible_v<T> && std::is_destructible_v<T>; case constraint_level::nothrow: return std::is_nothrow_move_constructible_v<T> && std::is_nothrow_destructible_v<T>; case constraint_level::trivial: return std::is_trivially_move_constructible_v<T> && std::is_trivially_destructible_v<T>; default: return false; } } template <class T> consteval bool has_destructibility(constraint_level level) { switch (level) { case constraint_level::none: return true; case constraint_level::nontrivial: return std::is_destructible_v<T>; case constraint_level::nothrow: return std::is_nothrow_destructible_v<T>; case constraint_level::trivial: return std::is_trivially_destructible_v<T>; default: return false; } } template <class T> class destruction_guard { public: explicit destruction_guard(T* p) noexcept : p_(p) {} destruction_guard(const destruction_guard&) = delete; ~destruction_guard() noexcept(std::is_nothrow_destructible_v<T>) { std::destroy_at(p_); } private: T* p_; }; template <class P, qualifier_type Q, bool NE> struct ptr_traits : inapplicable_traits {}; template <class P, qualifier_type Q, bool NE> requires(requires { *std::declval<add_qualifier_t<P, Q>>(); } && (!NE || noexcept(*std::declval<add_qualifier_t<P, Q>>()))) struct ptr_traits<P, Q, NE> : applicable_traits { using target_type = decltype(*std::declval<add_qualifier_t<P, Q>>()); }; template <class D, bool NE, class R, class... Args> concept invocable_dispatch = (NE && std::is_nothrow_invocable_r_v< R, D, Args...>) || (!NE && std::is_invocable_r_v<R, D, Args...>); template <class D, class P, qualifier_type Q, bool NE, class R, class... Args> concept invocable_dispatch_ptr_indirect = ptr_traits<P, Q, NE>::applicable && invocable_dispatch< D, NE, R, typename ptr_traits<P, Q, NE>::target_type, Args...>; template <class D, class P, qualifier_type Q, bool NE, class R, class... Args> concept invocable_dispatch_ptr_direct = invocable_dispatch< D, NE, R, add_qualifier_t<P, Q>, Args...> && (Q != qualifier_type::rv || (NE && std::is_nothrow_destructible_v<P>) || (!NE && std::is_destructible_v<P>)); template <bool NE, class R, class... Args> using func_ptr_t = std::conditional_t< NE, R (*)(Args...) noexcept, R (*)(Args...)>; template <class D, class R, class... Args> R invoke_dispatch(Args&&... args) { if constexpr (std::is_void_v<R>) { D{}(std::forward<Args>(args)...); } else { return D{}(std::forward<Args>(args)...); } } template <class D, class P, qualifier_type Q, class R, class... Args> R indirect_conv_dispatcher(add_qualifier_t<std::byte, Q> self, Args... args) noexcept(invocable_dispatch_ptr_indirect<D, P, Q, true, R, Args...>) { return invoke_dispatch<D, R>(*std::forward<add_qualifier_t<P, Q>>( *std::launder(reinterpret_cast<add_qualifier_ptr_t<P, Q>>(&self))), std::forward<Args>(args)...); } template <class D, class P, qualifier_type Q, class R, class... Args> R direct_conv_dispatcher(add_qualifier_t<std::byte, Q> self, Args... args) noexcept(invocable_dispatch_ptr_direct<D, P, Q, true, R, Args...>) { auto& qp = *std::launder( reinterpret_cast<add_qualifier_ptr_t<P, Q>>(&self)); if constexpr (Q == qualifier_type::rv) { destruction_guard guard{&qp}; return invoke_dispatch<D, R>( std::forward<add_qualifier_t<P, Q>>(qp), std::forward<Args>(args)...); } else { return invoke_dispatch<D, R>( std::forward<add_qualifier_t<P, Q>>(qp), std::forward<Args>(args)...); } } template <class D, qualifier_type Q, class R, class... Args> R default_conv_dispatcher(add_qualifier_t<std::byte, Q>, Args... args) noexcept(invocable_dispatch<D, true, R, std::nullptr_t, Args...>) { return invoke_dispatch<D, R>(nullptr, std::forward<Args>(args)...); } template <class P> void copying_dispatcher(std::byte& self, const std::byte& rhs) noexcept(has_copyability<P>(constraint_level::nothrow)) { std::construct_at(reinterpret_cast<P*>(&self), *std::launder(reinterpret_cast<const P*>(&rhs))); } template <std::size_t Len, std::size_t Align> void copying_default_dispatcher(std::byte& self, const std::byte& rhs) noexcept { std::uninitialized_copy_n( std::assume_aligned<Align>(&rhs), Len, std::assume_aligned<Align>(&self)); } template <class P> void relocation_dispatcher(std::byte& self, const std::byte& rhs) noexcept(has_relocatability<P>(constraint_level::nothrow)) { P* other = std::launder(reinterpret_cast<P*>(const_cast<std::byte*>(&rhs))); destruction_guard guard{other}; std::construct_at(reinterpret_cast<P*>(&self), std::move(*other)); } template <class P> void destruction_dispatcher(std::byte& self) noexcept(has_destructibility<P>(constraint_level::nothrow)) { std::destroy_at(std::launder(reinterpret_cast<P*>(&self))); } inline void destruction_default_dispatcher(std::byte&) noexcept {} template <class O> struct overload_traits : inapplicable_traits {}; template <qualifier_type Q, bool NE, class R, class... Args> struct overload_traits_impl : applicable_traits { template <bool IS_DIRECT, class D> struct meta_provider { template <class P> static constexpr auto get() -> func_ptr_t<NE, R, add_qualifier_t<std::byte, Q>, Args...> { if constexpr (!IS_DIRECT && invocable_dispatch_ptr_indirect<D, P, Q, NE, R, Args...>) { return &indirect_conv_dispatcher<D, P, Q, R, Args...>; } else if constexpr (IS_DIRECT && invocable_dispatch_ptr_direct<D, P, Q, NE, R, Args...>) { return &direct_conv_dispatcher<D, P, Q, R, Args...>; } else if constexpr (invocable_dispatch< D, NE, R, std::nullptr_t, Args...>) { return &default_conv_dispatcher<D, Q, R, Args...>; } else { return nullptr; } } }; struct resolver { overload_traits_impl operator()(add_qualifier_t<std::byte, Q>, Args...); }; template <bool IS_DIRECT, class D, class P> static constexpr bool applicable_ptr = meta_provider<IS_DIRECT, D>::template get<P>() != nullptr; static constexpr qualifier_type qualifier = Q; }; template <class R, class... Args> struct overload_traits<R(Args...)> : overload_traits_impl<qualifier_type::lv, false, R, Args...> {}; template <class R, class... Args> struct overload_traits<R(Args...) noexcept> : overload_traits_impl<qualifier_type::lv, true, R, Args...> {}; template <class R, class... Args> struct overload_traits<R(Args...) &> : overload_traits_impl<qualifier_type::lv, false, R, Args...> {}; template <class R, class... Args> struct overload_traits<R(Args...) & noexcept> : overload_traits_impl<qualifier_type::lv, true, R, Args...> {}; template <class R, class... Args> struct overload_traits<R(Args...) &&> : overload_traits_impl<qualifier_type::rv, false, R, Args...> {}; template <class R, class... Args> struct overload_traits<R(Args...) && noexcept> : overload_traits_impl<qualifier_type::rv, true, R, Args...> {}; template <class R, class... Args> struct overload_traits<R(Args...) const> : overload_traits_impl<qualifier_type::const_lv, false, R, Args...> {}; template <class R, class... Args> struct overload_traits<R(Args...) const noexcept> : overload_traits_impl<qualifier_type::const_lv, true, R, Args...> {}; template <class R, class... Args> struct overload_traits<R(Args...) const&> : overload_traits_impl<qualifier_type::const_lv, false, R, Args...> {}; template <class R, class... Args> struct overload_traits<R(Args...) const& noexcept> : overload_traits_impl<qualifier_type::const_lv, true, R, Args...> {}; template <class R, class... Args> struct overload_traits<R(Args...) const&&> : overload_traits_impl<qualifier_type::const_rv, false, R, Args...> {}; template <class R, class... Args> struct overload_traits<R(Args...) const&& noexcept> : overload_traits_impl<qualifier_type::const_rv, true, R, Args...> {}; template <class MP> struct dispatcher_meta { constexpr dispatcher_meta() noexcept : dispatcher(nullptr) {} template <class P> constexpr explicit dispatcher_meta(std::in_place_type_t<P>) noexcept : dispatcher(MP::template get<P>()) {} decltype(MP::template get<void>()) dispatcher; }; template <class... Ms> struct composite_meta_impl : Ms... { constexpr composite_meta_impl() noexcept = default; template <class P> constexpr explicit composite_meta_impl(std::in_place_type_t<P>) noexcept : Ms(std::in_place_type<P>)... {} }; template <class O, class I> struct meta_reduction : std::type_identity<O> {}; template <class... Ms, class I> requires(!std::is_void_v<I>) struct meta_reduction<composite_meta_impl<Ms...>, I> : std::type_identity<composite_meta_impl<Ms..., I>> {}; template <class... Ms1, class... Ms2> struct meta_reduction<composite_meta_impl<Ms1...>, composite_meta_impl<Ms2...>> : std::type_identity<composite_meta_impl<Ms1..., Ms2...>> {}; template <class O, class I> using meta_reduction_t = typename meta_reduction<O, I>::type; template <class... Ms> using composite_meta = recursive_reduction_t<meta_reduction_t, composite_meta_impl<>, Ms...>; template <class C> consteval bool is_conv_is_direct_well_formed() { if constexpr (requires { { C::is_direct } -> std::same_as<const bool&>; }) { if constexpr (is_consteval([] { return C::is_direct; })) { return true; } } return false; } template <class C, class... Os> struct conv_traits_impl : inapplicable_traits {}; template <class C, class... Os> requires(sizeof...(Os) > 0u && (overload_traits<Os>::applicable && ...)) struct conv_traits_impl<C, Os...> : applicable_traits { struct overload_resolver : overload_traits<Os>::resolver... { using overload_traits<Os>::resolver::operator()...; }; using meta = composite_meta_impl<dispatcher_meta<typename overload_traits<Os> ::template meta_provider<C::is_direct, typename C::dispatch_type>>...>; template <qualifier_type Q, class... Args> using matched_overload_traits = std::invoke_result_t< overload_resolver, add_qualifier_t<std::byte, Q>, Args...>; template <class P> static constexpr bool applicable_ptr = (overload_traits<Os>::template applicable_ptr< C::is_direct, typename C::dispatch_type, P> && ...); }; template <class C> struct conv_traits : inapplicable_traits {}; template <class C> requires( requires { typename C::dispatch_type; typename C::overload_types; } && is_conv_is_direct_well_formed<C>() && std::is_trivial_v<typename C::dispatch_type> && is_tuple_like_well_formed<typename C::overload_types>()) struct conv_traits<C> : instantiated_t<conv_traits_impl, typename C::overload_types, C> {}; template <bool NE> struct copyability_meta_provider { template <class P> static constexpr func_ptr_t<NE, void, std::byte&, const std::byte&> get() { if constexpr (has_copyability<P>(constraint_level::trivial)) { return ©ing_default_dispatcher<sizeof(P), alignof(P)>; } else { return ©ing_dispatcher<P>; } } }; template <bool NE> struct relocatability_meta_provider { template <class P> static constexpr func_ptr_t<NE, void, std::byte&, const std::byte&> get() { if constexpr (has_relocatability<P>(constraint_level::trivial)) { return ©ing_default_dispatcher<sizeof(P), alignof(P)>; } else { return &relocation_dispatcher<P>; } } }; template <bool NE> struct destructibility_meta_provider { template <class P> static constexpr func_ptr_t<NE, void, std::byte&> get() { if constexpr (has_destructibility<P>(constraint_level::trivial)) { return &destruction_default_dispatcher; } else { return &destruction_dispatcher<P>; } } }; template <template <bool> class MP, constraint_level C> struct lifetime_meta_traits : std::type_identity<void> {}; template <template <bool> class MP> struct lifetime_meta_traits<MP, constraint_level::nothrow> : std::type_identity<dispatcher_meta<MP<true>>> {}; template <template <bool> class MP> struct lifetime_meta_traits<MP, constraint_level::nontrivial> : std::type_identity<dispatcher_meta<MP<false>>> {}; template <template <bool> class MP, constraint_level C> using lifetime_meta_t = typename lifetime_meta_traits<MP, C>::type; template <class... As> class ___PRO_ENFORCE_EBO composite_accessor_impl : public As... { template <class> friend class pro::proxy; composite_accessor_impl() noexcept = default; composite_accessor_impl(const composite_accessor_impl&) noexcept = default; composite_accessor_impl& operator=(const composite_accessor_impl&) noexcept = default; }; template <template <class> class TA, class O, class I> struct composite_accessor_reduction : std::type_identity<O> {}; template <template <class> class TA, class... As, class I> requires(requires { typename TA<I>; } && std::is_trivial_v<TA<I>> && !std::is_final_v<TA<I>>) struct composite_accessor_reduction<TA, composite_accessor_impl<As...>, I> { using type = composite_accessor_impl<As..., TA<I>>; }; template <bool IS_DIRECT, class F> struct composite_accessor_helper { template <class C> requires(C::is_direct == IS_DIRECT) using single_accessor = typename C::template accessor<F>; template <class O, class I> using reduction_t = typename composite_accessor_reduction<single_accessor, O, I>::type; }; template <bool IS_DIRECT, class F, class... Cs> using composite_accessor = recursive_reduction_t< composite_accessor_helper<IS_DIRECT, F>::template reduction_t, composite_accessor_impl<>, Cs...>; template <class F> consteval bool is_facade_constraints_well_formed() { if constexpr (requires { { F::constraints } -> std::same_as<const proxiable_ptr_constraints&>; }) { if constexpr (is_consteval([] { return F::constraints; })) { return std::has_single_bit(F::constraints.max_align) && F::constraints.max_size % F::constraints.max_align == 0u; } } return false; } template <class R, class P> consteval bool is_reflection_type_well_formed() { if constexpr (std::is_constructible_v<R, std::in_place_type_t<P>>) { if constexpr (is_consteval([] { return R{std::in_place_type<P>}; })) { return true; } } return false; } template <class F, class... Cs> struct facade_conv_traits_impl : inapplicable_traits {}; template <class F, class... Cs> requires(conv_traits<Cs>::applicable && ...) struct facade_conv_traits_impl<F, Cs...> : applicable_traits { using conv_meta = composite_meta<typename conv_traits<Cs>::meta...>; using indirect_accessor = composite_accessor<false, F, Cs...>; using direct_accessor = composite_accessor<true, F, Cs...>; template <class P> static constexpr bool conv_applicable_ptr = (conv_traits<Cs>::template applicable_ptr<P> && ...); }; template <class F, class... Rs> struct facade_refl_traits_impl { using refl_meta = composite_meta<Rs...>; template <class P> static constexpr bool refl_applicable_ptr = (is_reflection_type_well_formed<Rs, P>() && ...); }; template <class F> struct facade_traits : inapplicable_traits {}; template <class F> requires( requires { typename F::convention_types; typename F::reflection_types; } && is_facade_constraints_well_formed<F>() && is_tuple_like_well_formed<typename F::convention_types>() && instantiated_t<facade_conv_traits_impl, typename F::convention_types, F> ::applicable && is_tuple_like_well_formed<typename F::reflection_types>()) struct facade_traits<F> : instantiated_t<facade_conv_traits_impl, typename F::convention_types, F>, instantiated_t<facade_refl_traits_impl, typename F::reflection_types, F> { using copyability_meta = lifetime_meta_t< copyability_meta_provider, F::constraints.copyability>; using relocatability_meta = lifetime_meta_t< relocatability_meta_provider, F::constraints.copyability == constraint_level::trivial ? constraint_level::trivial : F::constraints.relocatability>; using destructibility_meta = lifetime_meta_t< destructibility_meta_provider, F::constraints.destructibility>; using meta = composite_meta<copyability_meta, relocatability_meta, destructibility_meta, typename facade_traits::conv_meta, typename facade_traits::refl_meta>; static constexpr bool has_indirection = !std::is_same_v< typename facade_traits::indirect_accessor, composite_accessor_impl<>>; }; using ptr_prototype = void*[2]; template <class M> struct meta_ptr_indirect_impl { constexpr meta_ptr_indirect_impl() noexcept : ptr_(nullptr) {}; template <class P> constexpr explicit meta_ptr_indirect_impl(std::in_place_type_t<P>) noexcept : ptr_(&storage<P>) {} bool has_value() const noexcept { return ptr_ != nullptr; } void reset() noexcept { ptr_ = nullptr; } const M* operator->() const noexcept { return ptr_; } private: const M* ptr_; template <class P> static constexpr M storage{std::in_place_type<P>}; }; template <class M, class DM> struct meta_ptr_direct_impl : private M { using M::M; bool has_value() const noexcept { return this->DM::dispatcher != nullptr; } void reset() noexcept { this->DM::dispatcher = nullptr; } const M* operator->() const noexcept { return this; } }; template <class M> struct meta_ptr_traits_impl : std::type_identity<meta_ptr_indirect_impl<M>> {}; template <class MP, class... Ms> struct meta_ptr_traits_impl<composite_meta_impl<dispatcher_meta<MP>, Ms...>> : std::type_identity<meta_ptr_direct_impl<composite_meta_impl< dispatcher_meta<MP>, Ms...>, dispatcher_meta<MP>>> {}; template <class M> struct meta_ptr_traits : std::type_identity<meta_ptr_indirect_impl<M>> {}; template <class M> requires(sizeof(M) <= sizeof(ptr_prototype) && alignof(M) <= alignof(ptr_prototype) && std::is_nothrow_default_constructible_v<M> && std::is_trivially_copyable_v<M>) struct meta_ptr_traits<M> : meta_ptr_traits_impl<M> {}; template <class M> using meta_ptr = typename meta_ptr_traits<M>::type; template <class MP> struct meta_ptr_reset_guard { public: explicit meta_ptr_reset_guard(MP& meta) noexcept : meta_(meta) {} meta_ptr_reset_guard(const meta_ptr_reset_guard&) = delete; ~meta_ptr_reset_guard() { meta_.reset(); } private: MP& meta_; }; template <class F> struct proxy_helper { static inline const auto& get_meta(const proxy<F>& p) noexcept { return *p.meta_.operator->(); } template <class C, qualifier_type Q, class... Args> static decltype(auto) invoke(add_qualifier_t<proxy<F>, Q> p, Args&&... args) { using OverloadTraits = typename conv_traits<C> ::template matched_overload_traits<Q, Args...>; auto dispatcher = p.meta_->template dispatcher_meta<typename OverloadTraits ::template meta_provider<C::is_direct, typename C::dispatch_type>> ::dispatcher; if constexpr (C::is_direct && OverloadTraits::qualifier == qualifier_type::rv) { meta_ptr_reset_guard guard{p.meta_}; return dispatcher(std::forward<add_qualifier_t<std::byte, Q>>(*p.ptr_), std::forward<Args>(args)...); } else { return dispatcher(std::forward<add_qualifier_t<std::byte, Q>>(*p.ptr_), std::forward<Args>(args)...); } } template <class A, qualifier_type Q> static add_qualifier_t<proxy<F>, Q> access(add_qualifier_t<A, Q> a) { if constexpr (std::is_base_of_v<A, proxy<F>>) { return static_cast<add_qualifier_t<proxy<F>, Q>>( std::forward<add_qualifier_t<A, Q>>(a)); } else { return reinterpret_cast<add_qualifier_t<proxy<F>, Q>>( *(reinterpret_cast<add_qualifier_ptr_t<std::byte, Q>>( static_cast<add_qualifier_ptr_t< typename facade_traits<F>::indirect_accessor, Q>>( std::addressof(a))) - offsetof(proxy<F>, ia_))); } } }; } // namespace details template <class F> concept facade = details::facade_traits<F>::applicable; template <class P, class F> concept proxiable = facade<F> && sizeof(P) <= F::constraints.max_size && alignof(P) <= F::constraints.max_align && details::has_copyability<P>(F::constraints.copyability) && details::has_relocatability<P>(F::constraints.relocatability) && details::has_destructibility<P>(F::constraints.destructibility) && details::facade_traits<F>::template conv_applicable_ptr<P> && details::facade_traits<F>::template refl_applicable_ptr<P>; template <class F> class proxy : public details::facade_traits<F>::direct_accessor { static_assert(facade<F>); friend struct details::proxy_helper<F>; using _Traits = details::facade_traits<F>; public: proxy() noexcept = default; proxy(std::nullptr_t) noexcept {} proxy(const proxy&) noexcept requires(F::constraints.copyability == constraint_level::trivial) = default; proxy(const proxy& rhs) noexcept(F::constraints.copyability == constraint_level::nothrow) requires(F::constraints.copyability == constraint_level::nontrivial || F::constraints.copyability == constraint_level::nothrow) { if (rhs.meta_.has_value()) { rhs.meta_->_Traits::copyability_meta::dispatcher(*ptr_, *rhs.ptr_); meta_ = rhs.meta_; } } proxy(proxy&& rhs) noexcept(F::constraints.relocatability == constraint_level::nothrow) requires(F::constraints.relocatability >= constraint_level::nontrivial && F::constraints.copyability != constraint_level::trivial) { if (rhs.meta_.has_value()) { details::meta_ptr_reset_guard guard{rhs.meta_}; if constexpr (F::constraints.relocatability == constraint_level::trivial) { std::ranges::uninitialized_copy(rhs.ptr_, ptr_); } else { rhs.meta_->_Traits::relocatability_meta::dispatcher(*ptr_, *rhs.ptr_); } meta_ = rhs.meta_; } } template <class P> proxy(P&& ptr) noexcept(std::is_nothrow_constructible_v<std::decay_t<P>, P>) requires(proxiable<std::decay_t<P>, F> && std::is_constructible_v<std::decay_t<P>, P>) { initialize<std::decay_t<P>>(std::forward<P>(ptr)); } template <proxiable<F> P, class... Args> explicit proxy(std::in_place_type_t<P>, Args&&... args) noexcept(std::is_nothrow_constructible_v<P, Args...>) requires(std::is_constructible_v<P, Args...>) { initialize<P>(std::forward<Args>(args)...); } template <proxiable<F> P, class U, class... Args> explicit proxy(std::in_place_type_t<P>, std::initializer_list<U> il, Args&&... args) noexcept(std::is_nothrow_constructible_v< P, std::initializer_list<U>&, Args...>) requires(std::is_constructible_v<P, std::initializer_list<U>&, Args...>) { initialize<P>(il, std::forward<Args>(args)...); } proxy& operator=(std::nullptr_t) noexcept(F::constraints.destructibility >= constraint_level::nothrow) requires(F::constraints.destructibility >= constraint_level::nontrivial) { reset(); return *this; } proxy& operator=(const proxy&) noexcept requires(F::constraints.copyability == constraint_level::trivial) = default; proxy& operator=(const proxy& rhs) noexcept(F::constraints.copyability >= constraint_level::nothrow && F::constraints.destructibility >= constraint_level::nothrow) requires((F::constraints.copyability == constraint_level::nontrivial || F::constraints.copyability == constraint_level::nothrow) && F::constraints.destructibility >= constraint_level::nontrivial) { if (this != &rhs) { if constexpr (F::constraints.copyability == constraint_level::nothrow) { std::destroy_at(this); std::construct_at(this, rhs); } else { *this = proxy{rhs}; } } return *this; } proxy& operator=(proxy&& rhs) noexcept(F::constraints.relocatability >= constraint_level::nothrow && F::constraints.destructibility >= constraint_level::nothrow) requires(F::constraints.relocatability >= constraint_level::nontrivial && F::constraints.destructibility >= constraint_level::nontrivial && F::constraints.copyability != constraint_level::trivial) { if (this != &rhs) { reset(); std::construct_at(this, std::move(rhs)); } return *this; } template <class P> proxy& operator=(P&& ptr) noexcept(std::is_nothrow_constructible_v<std::decay_t<P>, P> && F::constraints.destructibility >= constraint_level::nothrow) requires(proxiable<std::decay_t<P>, F> && std::is_constructible_v<std::decay_t<P>, P> && F::constraints.destructibility >= constraint_level::nontrivial) { if constexpr (std::is_nothrow_constructible_v<std::decay_t<P>, P>) { std::destroy_at(this); initialize<std::decay_t<P>>(std::forward<P>(ptr)); } else { *this = proxy{std::forward<P>(ptr)}; } return *this; } ~proxy() requires(F::constraints.destructibility == constraint_level::trivial) = default; ~proxy() noexcept(F::constraints.destructibility == constraint_level::nothrow) requires(F::constraints.destructibility == constraint_level::nontrivial || F::constraints.destructibility == constraint_level::nothrow) { if (meta_.has_value()) { meta_->_Traits::destructibility_meta::dispatcher(*ptr_); } } bool has_value() const noexcept { return meta_.has_value(); } explicit operator bool() const noexcept { return meta_.has_value(); } void reset() noexcept(F::constraints.destructibility >= constraint_level::nothrow) requires(F::constraints.destructibility >= constraint_level::nontrivial) { std::destroy_at(this); meta_.reset(); } void swap(proxy& rhs) noexcept(F::constraints.relocatability >= constraint_level::nothrow || F::constraints.copyability == constraint_level::trivial) requires(F::constraints.relocatability >= constraint_level::nontrivial || F::constraints.copyability == constraint_level::trivial) { if constexpr (F::constraints.relocatability == constraint_level::trivial || F::constraints.copyability == constraint_level::trivial) { std::swap(meta_, rhs.meta_); std::swap(ptr_, rhs.ptr); } else { if (meta_.has_value()) { if (rhs.meta_.has_value()) { proxy temp = std::move(*this); std::construct_at(this, std::move(rhs)); std::construct_at(&rhs, std::move(temp)); } else { std::construct_at(&rhs, std::move(*this)); } } else if (rhs.meta_.has_value()) { std::construct_at(this, std::move(rhs)); } } } template <proxiable<F> P, class... Args> P& emplace(Args&&... args) noexcept(std::is_nothrow_constructible_v<P, Args...> && F::constraints.destructibility >= constraint_level::nothrow) requires(std::is_constructible_v<P, Args...> && F::constraints.destructibility >= constraint_level::nontrivial) { reset(); return initialize<P>(std::forward<Args>(args)...); } template <proxiable<F> P, class U, class... Args> P& emplace(std::initializer_list<U> il, Args&&... args) noexcept(std::is_nothrow_constructible_v< P, std::initializer_list<U>&, Args...> && F::constraints.destructibility >= constraint_level::nothrow) requires(std::is_constructible_v<P, std::initializer_list<U>&, Args...> && F::constraints.destructibility >= constraint_level::nontrivial) { reset(); return initialize<P>(il, std::forward<Args>(args)...); } auto operator->() noexcept requires(_Traits::has_indirection) { return std::addressof(ia_); } auto operator->() const noexcept requires(_Traits::has_indirection) { return std::addressof(ia_); } auto& operator*() & noexcept requires(_Traits::has_indirection) { return ia_; } auto& operator*() const& noexcept requires(_Traits::has_indirection) { return ia_; } auto&& operator*() && noexcept requires(_Traits::has_indirection) { return std::forward<typename _Traits::indirect_accessor>(ia_); } auto&& operator*() const&& noexcept requires(_Traits::has_indirection) { return std::forward<const typename _Traits::indirect_accessor>(ia_); } friend void swap(proxy& lhs, proxy& rhs) noexcept(noexcept(lhs.swap(rhs))) { lhs.swap(rhs); } friend bool operator==(const proxy& lhs, std::nullptr_t) noexcept { return !lhs.has_value(); } private: template <class P, class... Args> P& initialize(Args&&... args) { std::construct_at(reinterpret_cast<P*>(ptr_), std::forward<Args>(args)...); meta_ = details::meta_ptr<typename _Traits::meta>{std::in_place_type<P>}; return *std::launder(reinterpret_cast<P*>(ptr_)); } [[___PRO_NO_UNIQUE_ADDRESS_ATTRIBUTE]] typename _Traits::indirect_accessor ia_; details::meta_ptr<typename _Traits::meta> meta_; alignas(F::constraints.max_align) std::byte ptr_[F::constraints.max_size]; }; template <class C, class F, class... Args> decltype(auto) proxy_invoke(proxy<F>& p, Args&&... args) { return details::proxy_helper<F>::template invoke< C, details::qualifier_type::lv>(p, std::forward<Args>(args)...); } template <class C, class F, class... Args> decltype(auto) proxy_invoke(const proxy<F>& p, Args&&... args) { return details::proxy_helper<F>::template invoke< C, details::qualifier_type::const_lv>(p, std::forward<Args>(args)...); } template <class C, class F, class... Args> decltype(auto) proxy_invoke(proxy<F>&& p, Args&&... args) { return details::proxy_helper<F>::template invoke< C, details::qualifier_type::rv>( std::forward<proxy<F>>(p), std::forward<Args>(args)...); } template <class C, class F, class... Args> decltype(auto) proxy_invoke(const proxy<F>&& p, Args&&... args) { return details::proxy_helper<F>::template invoke< C, details::qualifier_type::const_rv>( std::forward<const proxy<F>>(p), std::forward<Args>(args)...); } template <class F, class A> proxy<F>& access_proxy(A& a) noexcept { return details::proxy_helper<F>::template access< A, details::qualifier_type::lv>(a); } template <class F, class A> const proxy<F>& access_proxy(const A& a) noexcept { return details::proxy_helper<F>::template access< A, details::qualifier_type::const_lv>(a); } template <class F, class A> proxy<F>&& access_proxy(A&& a) noexcept { return details::proxy_helper<F>::template access< A, details::qualifier_type::rv>(std::forward<A>(a)); } template <class F, class A> const proxy<F>&& access_proxy(const A&& a) noexcept { return details::proxy_helper<F>::template access< A, details::qualifier_type::const_rv>(std::forward<const A>(a)); } template <class R, class F> const R& proxy_reflect(const proxy<F>& p) noexcept { return details::proxy_helper<F>::get_meta(p); } namespace details { template <class T> class inplace_ptr { public: template <class... Args> inplace_ptr(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>) requires(std::is_constructible_v<T, Args...>) : value_(std::forward<Args>(args)...) {} inplace_ptr(const inplace_ptr&) noexcept(std::is_nothrow_copy_constructible_v<T>) = default; inplace_ptr(inplace_ptr&&) noexcept(std::is_nothrow_move_constructible_v<T>) = default; T* operator->() noexcept { return &value_; } const T* operator->() const noexcept { return &value_; } T& operator*() & noexcept { return value_; } const T& operator*() const& noexcept { return value_; } T&& operator*() && noexcept { return std::forward<T>(value_); } const T&& operator*() const&& noexcept { return std::forward<const T>(value_); } private: T value_; }; #if __STDC_HOSTED__ template <class T, class Alloc> static auto rebind_allocator(const Alloc& alloc) { return typename std::allocator_traits<Alloc>::template rebind_alloc<T>(alloc); } template <class T, class Alloc, class... Args> static T* allocate(const Alloc& alloc, Args&&... args) { auto al = rebind_allocator<T>(alloc); auto deleter = [&](T* ptr) { al.deallocate(ptr, 1); }; std::unique_ptr<T, decltype(deleter)> result{al.allocate(1), deleter}; std::construct_at(result.get(), std::forward<Args>(args)...); return result.release(); } template <class Alloc, class T> static void deallocate(const Alloc& alloc, T* ptr) { auto al = rebind_allocator<T>(alloc); std::destroy_at(ptr); al.deallocate(ptr, 1); } template <class T, class Alloc> class allocated_ptr { public: template <class... Args> allocated_ptr(const Alloc& alloc, Args&&... args) requires(std::is_constructible_v<T, Args...>) : alloc_(alloc), ptr_(allocate<T>(alloc, std::forward<Args>(args)...)) {} allocated_ptr(const allocated_ptr& rhs) requires(std::is_copy_constructible_v<T>) : alloc_(rhs.alloc_), ptr_(rhs.ptr_ == nullptr ? nullptr : allocate<T>(alloc_, std::as_const(*rhs.ptr_))) {} allocated_ptr(allocated_ptr&& rhs) noexcept(std::is_nothrow_move_constructible_v<Alloc>) : alloc_(std::move(rhs.alloc_)), ptr_(std::exchange(rhs.ptr_, nullptr)) {} ~allocated_ptr() { if (ptr_ != nullptr) { deallocate(alloc_, ptr_); } } T* operator->() noexcept { return ptr_; } const T* operator->() const noexcept { return ptr_; } T& operator*() & noexcept { return *ptr_; } const T& operator*() const& noexcept { return *ptr_; } T&& operator*() && noexcept { return std::forward<T>(*ptr_); } const T&& operator*() const&& noexcept { return std::forward<const T>(*ptr_); } private: [[___PRO_NO_UNIQUE_ADDRESS_ATTRIBUTE]] Alloc alloc_; T* ptr_; }; template <class T, class Alloc> class compact_ptr { public: template <class... Args> compact_ptr(const Alloc& alloc, Args&&... args) requires(std::is_constructible_v<T, Args...>) : ptr_(allocate<storage>(alloc, alloc, std::forward<Args>(args)...)) {} compact_ptr(const compact_ptr& rhs) requires(std::is_copy_constructible_v<T>) : ptr_(rhs.ptr_ == nullptr ? nullptr : allocate<storage>(rhs.ptr_->alloc, rhs.ptr_->alloc, std::as_const(rhs.ptr_->value))) {} compact_ptr(compact_ptr&& rhs) noexcept : ptr_(std::exchange(rhs.ptr_, nullptr)) {} ~compact_ptr() { if (ptr_ != nullptr) { deallocate(ptr_->alloc, ptr_); } } T* operator->() noexcept { return &ptr_->value; } const T* operator->() const noexcept { return &ptr_->value; } T& operator*() & noexcept { return ptr_->value; } const T& operator*() const& noexcept { return ptr_->value; } T&& operator*() && noexcept { return std::forward<T>(ptr_->value); } const T&& operator*() const&& noexcept { return std::forward<const T>(ptr_->value); } private: struct storage { template <class... Args> explicit storage(const Alloc& alloc, Args&&... args) : value(std::forward<Args>(args)...), alloc(alloc) {} T value; Alloc alloc; }; storage* ptr_; }; template <class F, class T, class Alloc, class... Args> proxy<F> allocate_proxy_impl(const Alloc& alloc, Args&&... args) { if constexpr (proxiable<allocated_ptr<T, Alloc>, F>) { return proxy<F>{std::in_place_type<allocated_ptr<T, Alloc>>, alloc, std::forward<Args>(args)...}; } else { return proxy<F>{std::in_place_type<compact_ptr<T, Alloc>>, alloc, std::forward<Args>(args)...}; } } template <class F, class T, class... Args> proxy<F> make_proxy_impl(Args&&... args) { if constexpr (proxiable<inplace_ptr<T>, F>) { return proxy<F>{std::in_place_type<inplace_ptr<T>>, std::forward<Args>(args)...}; } else { return allocate_proxy_impl<F, T>( std::allocator<T>{}, std::forward<Args>(args)...); } } #endif // __STDC_HOSTED__ } // namespace details template <class T, class F> concept inplace_proxiable_target = proxiable<details::inplace_ptr<T>, F>; template <facade F, inplace_proxiable_target<F> T, class... Args> proxy<F> make_proxy_inplace(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>) { return proxy<F>{std::in_place_type<details::inplace_ptr<T>>, std::forward<Args>(args)...}; } template <facade F, inplace_proxiable_target<F> T, class U, class... Args> proxy<F> make_proxy_inplace(std::initializer_list<U> il, Args&&... args) noexcept(std::is_nothrow_constructible_v< T, std::initializer_list<U>&, Args...>) { return proxy<F>{std::in_place_type<details::inplace_ptr<T>>, il, std::forward<Args>(args)...}; } template <facade F, class T> proxy<F> make_proxy_inplace(T&& value) noexcept(std::is_nothrow_constructible_v<std::decay_t<T>, T>) requires(inplace_proxiable_target<std::decay_t<T>, F>) { return proxy<F>{std::in_place_type<details::inplace_ptr<std::decay_t<T>>>, std::forward<T>(value)}; } #if __STDC_HOSTED__ template <facade F, class T, class Alloc, class... Args> proxy<F> allocate_proxy(const Alloc& alloc, Args&&... args) { return details::allocate_proxy_impl<F, T>(alloc, std::forward<Args>(args)...); } template <facade F, class T, class Alloc, class U, class... Args> proxy<F> allocate_proxy(const Alloc& alloc, std::initializer_list<U> il, Args&&... args) { return details::allocate_proxy_impl<F, T>( alloc, il, std::forward<Args>(args)...); } template <facade F, class Alloc, class T> proxy<F> allocate_proxy(const Alloc& alloc, T&& value) { return details::allocate_proxy_impl<F, std::decay_t<T>>( alloc, std::forward<T>(value)); } template <facade F, class T, class... Args> proxy<F> make_proxy(Args&&... args) { return details::make_proxy_impl<F, T>(std::forward<Args>(args)...); } template <facade F, class T, class U, class... Args> proxy<F> make_proxy(std::initializer_list<U> il, Args&&... args) { return details::make_proxy_impl<F, T>(il, std::forward<Args>(args)...); } template <facade F, class T> proxy<F> make_proxy(T&& value) { return details::make_proxy_impl<F, std::decay_t<T>>(std::forward<T>(value)); } #endif // __STDC_HOSTED__ #define ___PRO_DIRECT_FUNC_IMPL(...) \ noexcept(noexcept(__VA_ARGS__)) requires(requires { __VA_ARGS__; }) \ { return __VA_ARGS__; } #define ___PRO_DEF_MEM_ACCESSOR_TEMPLATE(__MACRO, ...) \ template <class __F, class __C, class... __Os> \ struct ___PRO_ENFORCE_EBO accessor { accessor() = delete; }; \ template <class __F, class __C, class... __Os> \ requires(sizeof...(__Os) > 1u && \ (::std::is_trivial_v<accessor<__F, __C, __Os>> && ...)) \ struct accessor<__F, __C, __Os...> : accessor<__F, __C, __Os>... \ { using accessor<__F, __C, __Os>:: __VA_ARGS__ ...; }; \ __MACRO(, *this, __VA_ARGS__); \ __MACRO(noexcept, *this, __VA_ARGS__); \ __MACRO(&, *this, __VA_ARGS__); \ __MACRO(& noexcept, *this, __VA_ARGS__); \ __MACRO(&&, ::std::forward<accessor>(*this), __VA_ARGS__); \ __MACRO(&& noexcept, ::std::forward<accessor>(*this), __VA_ARGS__); \ __MACRO(const, *this, __VA_ARGS__); \ __MACRO(const noexcept, *this, __VA_ARGS__); \ __MACRO(const&, *this, __VA_ARGS__); \ __MACRO(const& noexcept, *this, __VA_ARGS__); \ __MACRO(const&&, ::std::forward<const accessor>(*this), __VA_ARGS__); \ __MACRO(const&& noexcept, ::std::forward<const accessor>(*this), \ __VA_ARGS__); #define ___PRO_DEF_FREE_ACCESSOR_TEMPLATE(__MACRO, ...) \ template <class __F, class __C, class... __Os> \ struct ___PRO_ENFORCE_EBO accessor { accessor() = delete; }; \ template <class __F, class __C, class... __Os> \ requires(sizeof...(__Os) > 1u && \ (::std::is_trivial_v<accessor<__F, __C, __Os>> && ...)) \ struct accessor<__F, __C, __Os...> : accessor<__F, __C, __Os>... {}; \ __MACRO(,, accessor& __self, __self, __VA_ARGS__); \ __MACRO(noexcept, noexcept, accessor& __self, __self, __VA_ARGS__); \ __MACRO(&,, accessor& __self, __self, __VA_ARGS__); \ __MACRO(& noexcept, noexcept, accessor& __self, __self, __VA_ARGS__); \ __MACRO(&&,, accessor&& __self, \ ::std::forward<accessor>(__self), __VA_ARGS__); \ __MACRO(&& noexcept, noexcept, accessor&& __self, \ ::std::forward<accessor>(__self), __VA_ARGS__); \ __MACRO(const,, const accessor& __self, __self, __VA_ARGS__); \ __MACRO(const noexcept, noexcept, const accessor& __self, \ __self, __VA_ARGS__); \ __MACRO(const&,, const accessor& __self, __self, __VA_ARGS__); \ __MACRO(const& noexcept, noexcept, const accessor& __self, \ __self, __VA_ARGS__); \ __MACRO(const&&,, const accessor&& __self, \ ::std::forward<const accessor>(__self), __VA_ARGS__); \ __MACRO(const&& noexcept, noexcept, const accessor&& __self, \ ::std::forward<const accessor>(__self), __VA_ARGS__); namespace details { constexpr std::size_t invalid_size = std::numeric_limits<std::size_t>::max(); constexpr constraint_level invalid_cl = static_cast<constraint_level>( std::numeric_limits<std::underlying_type_t<constraint_level>>::min()); consteval auto normalize(proxiable_ptr_constraints value) { if (value.max_size == invalid_size) { value.max_size = sizeof(ptr_prototype); } if (value.max_align == invalid_size) { value.max_align = alignof(ptr_prototype); } if (value.copyability == invalid_cl) { value.copyability = constraint_level::none; } if (value.relocatability == invalid_cl) { value.relocatability = constraint_level::nothrow; } if (value.destructibility == invalid_cl) { value.destructibility = constraint_level::nothrow; } return value; } consteval auto make_restricted_layout(proxiable_ptr_constraints value, std::size_t max_size, std::size_t max_align) { if (value.max_size > max_size) { value.max_size = max_size; } if (value.max_align > max_align) { value.max_align = max_align; } return value; } consteval auto make_copyable(proxiable_ptr_constraints value, constraint_level cl) { if (value.copyability < cl) { value.copyability = cl; } return value; } consteval auto make_relocatable(proxiable_ptr_constraints value, constraint_level cl) { if (value.relocatability < cl) { value.relocatability = cl; } return value; } consteval auto make_destructible(proxiable_ptr_constraints value, constraint_level cl) { if (value.destructibility < cl) { value.destructibility = cl; } return value; } consteval auto merge_constraints(proxiable_ptr_constraints a, proxiable_ptr_constraints b) { a = make_restricted_layout(a, b.max_size, b.max_align); a = make_copyable(a, b.copyability); a = make_relocatable(a, b.relocatability); a = make_destructible(a, b.destructibility); return a; } consteval std::size_t max_align_of(std::size_t value) { value &= ~value + 1u; return value < alignof(std::max_align_t) ? value : alignof(std::max_align_t); } template <bool IS_DIRECT, class D, class... Os> struct conv_impl { static constexpr bool is_direct = IS_DIRECT; using dispatch_type = D; using overload_types = std::tuple<Os...>; template <class F> using accessor = typename D::template accessor<F, conv_impl, Os...>; }; template <class Cs, class Rs, proxiable_ptr_constraints C> struct facade_impl { using convention_types = Cs; using reflection_types = Rs; static constexpr proxiable_ptr_constraints constraints = C; }; #define ___PRO_DEF_UPWARD_CONVERSION_ACCESSOR(Q, SELF, ...) \ template <class F2, class C> \ struct accessor<F2, C, proxy<F>() Q> { \ __VA_ARGS__ () Q { \ if (access_proxy<F2>(SELF).has_value()) { \ return proxy_invoke<C>(access_proxy<F2>(SELF)); \ } \ return nullptr; \ } \ } template <class F> struct upward_conversion_dispatch { using Base = proxy<F>; template <class T> Base operator()(T&& value) noexcept(std::is_nothrow_convertible_v<T, Base>) requires(std::is_convertible_v<T, Base>) { return static_cast<Base>(std::forward<T>(value)); } ___PRO_DEF_MEM_ACCESSOR_TEMPLATE( ___PRO_DEF_UPWARD_CONVERSION_ACCESSOR, operator Base) }; #undef ___PRO_DEF_UPWARD_CONVERSION_ACCESSOR template <class O, class I> struct add_tuple_reduction : std::type_identity<O> {}; template <class... Os, class I> requires(!std::is_same_v<I, Os> && ...) struct add_tuple_reduction<std::tuple<Os...>, I> : std::type_identity<std::tuple<Os..., I>> {}; template <class T, class U> using add_tuple_t = typename add_tuple_reduction<T, U>::type; template <class O, class... Is> using merge_tuple_impl_t = recursive_reduction_t<add_tuple_t, O, Is...>; template <class T, class U> using merge_tuple_t = instantiated_t<merge_tuple_impl_t, U, T>; template <bool IS_DIRECT, class D> struct merge_conv_traits { template <class... Os> using type = conv_impl<IS_DIRECT, D, Os...>; }; template <class C0, class C1> using merge_conv_t = instantiated_t< merge_conv_traits<C0::is_direct, typename C0::dispatch_type>::template type, merge_tuple_t<typename C0::overload_types, typename C1::overload_types>>; template <class Cs0, class C1, class C> struct add_conv_reduction; template <class... Cs0, class C1, class... Cs2, class C> struct add_conv_reduction<std::tuple<Cs0...>, std::tuple<C1, Cs2...>, C> : add_conv_reduction<std::tuple<Cs0..., C1>, std::tuple<Cs2...>, C> {}; template <class... Cs0, class C1, class... Cs2, class C> requires(C::is_direct == C1::is_direct && std::is_same_v< typename C::dispatch_type, typename C1::dispatch_type>) struct add_conv_reduction<std::tuple<Cs0...>, std::tuple<C1, Cs2...>, C> : std::type_identity<std::tuple<Cs0..., merge_conv_t<C1, C>, Cs2...>> {}; template <class... Cs, class C> struct add_conv_reduction<std::tuple<Cs...>, std::tuple<>, C> : std::type_identity<std::tuple<Cs..., merge_conv_t< conv_impl<C::is_direct, typename C::dispatch_type>, C>>> {}; template <class Cs, class C> using add_conv_t = typename add_conv_reduction<std::tuple<>, Cs, C>::type; template <class F, constraint_level CL> using copy_conversion_overload = proxy<F>() const& noexcept(CL >= constraint_level::nothrow); template <class F, constraint_level CL> using move_conversion_overload = proxy<F>() && noexcept(CL >= constraint_level::nothrow); template <class Cs, class F, constraint_level CCL, constraint_level RCL> struct add_upward_conversion_conv : std::type_identity<add_conv_t<Cs, conv_impl<true, upward_conversion_dispatch<F>, copy_conversion_overload<F, CCL>, move_conversion_overload<F, RCL>>>> {}; template <class Cs, class F, constraint_level RCL> struct add_upward_conversion_conv<Cs, F, constraint_level::none, RCL> : std::type_identity<add_conv_t<Cs, conv_impl<true, upward_conversion_dispatch<F>, move_conversion_overload<F, RCL>>>> {}; template <class Cs, class F, constraint_level CCL> struct add_upward_conversion_conv<Cs, F, CCL, constraint_level::none> : std::type_identity<add_conv_t<Cs, conv_impl<true, upward_conversion_dispatch<F>, copy_conversion_overload<F, CCL>>>> {}; template <class Cs, class F> struct add_upward_conversion_conv< Cs, F, constraint_level::none, constraint_level::none> : std::type_identity<Cs> {}; template <class Cs0, class... Cs1> using merge_conv_tuple_t = recursive_reduction_t<add_conv_t, Cs0, Cs1...>; template <class Cs, class F, bool WithUpwardConversion> using merge_facade_conv_t = typename add_upward_conversion_conv< instantiated_t<merge_conv_tuple_t, typename F::convention_types, Cs>, F, WithUpwardConversion ? F::constraints.copyability : constraint_level::none, (WithUpwardConversion && F::constraints.copyability != constraint_level::trivial) ? F::constraints.relocatability : constraint_level::none>::type; template <std::size_t N> struct sign { consteval sign(const char (&str)[N]) { for (std::size_t i = 0; i < N; ++i) { value[i] = str[i]; } } char value[N]; }; template <std::size_t N> sign(const char (&str)[N]) -> sign<N>; } // namespace details template <class Cs, class Rs, proxiable_ptr_constraints C> struct basic_facade_builder { template <class D, class... Os> requires(sizeof...(Os) > 0u && (details::overload_traits<Os>::applicable && ...)) using add_indirect_convention = basic_facade_builder<details::add_conv_t< Cs, details::conv_impl<false, D, Os...>>, Rs, C>; template <class D, class... Os> requires(sizeof...(Os) > 0u && (details::overload_traits<Os>::applicable && ...)) using add_direct_convention = basic_facade_builder<details::add_conv_t< Cs, details::conv_impl<true, D, Os...>>, Rs, C>; template <class D, class... Os> requires(sizeof...(Os) > 0u && (details::overload_traits<Os>::applicable && ...)) using add_convention = add_indirect_convention<D, Os...>; template <class R> using add_reflection = basic_facade_builder< Cs, details::add_tuple_t<Rs, R>, C>; template <facade F, bool WithUpwardConversion = false> using add_facade = basic_facade_builder< details::merge_facade_conv_t<Cs, F, WithUpwardConversion>, details::merge_tuple_t<Rs, typename F::reflection_types>, details::merge_constraints(C, F::constraints)>; template <std::size_t PtrSize, std::size_t PtrAlign = details::max_align_of(PtrSize)> requires(std::has_single_bit(PtrAlign) && PtrSize % PtrAlign == 0u) using restrict_layout = basic_facade_builder< Cs, Rs, details::make_restricted_layout(C, PtrSize, PtrAlign)>; template <constraint_level CL> using support_copy = basic_facade_builder< Cs, Rs, details::make_copyable(C, CL)>; template <constraint_level CL> using support_relocation = basic_facade_builder< Cs, Rs, details::make_relocatable(C, CL)>; template <constraint_level CL> using support_destruction = basic_facade_builder< Cs, Rs, details::make_destructible(C, CL)>; using build = details::facade_impl<Cs, Rs, details::normalize(C)>; basic_facade_builder() = delete; }; using facade_builder = basic_facade_builder<std::tuple<>, std::tuple<>, proxiable_ptr_constraints{ .max_size = details::invalid_size, .max_align = details::invalid_size, .copyability = details::invalid_cl, .relocatability = details::invalid_cl, .destructibility = details::invalid_cl}>; template <details::sign Sign, bool Rhs = false> struct operator_dispatch; #define ___PRO_DEF_LHS_LEFT_OP_ACCESSOR(Q, SELF, ...) \ template <class F, class C, class R> \ struct accessor<F, C, R() Q> { \ R __VA_ARGS__ () Q { return proxy_invoke<C>(access_proxy<F>(SELF)); } \ } #define ___PRO_DEF_LHS_ANY_OP_ACCESSOR(Q, SELF, ...) \ template <class F, class C, class R, class... Args> \ struct accessor<F, C, R(Args...) Q> { \ R __VA_ARGS__ (Args... args) Q { \ return proxy_invoke<C>( \ access_proxy<F>(SELF), std::forward<Args>(args)...); \ } \ } #define ___PRO_DEF_LHS_UNARY_OP_ACCESSOR ___PRO_DEF_LHS_ANY_OP_ACCESSOR #define ___PRO_DEF_LHS_BINARY_OP_ACCESSOR ___PRO_DEF_LHS_ANY_OP_ACCESSOR #define ___PRO_DEF_LHS_ALL_OP_ACCESSOR ___PRO_DEF_LHS_ANY_OP_ACCESSOR #define ___PRO_LHS_LEFT_OP_DISPATCH_BODY_IMPL(...) \ template <class T> \ decltype(auto) operator()(T&& self) \ ___PRO_DIRECT_FUNC_IMPL(__VA_ARGS__ std::forward<T>(self)) #define ___PRO_LHS_UNARY_OP_DISPATCH_BODY_IMPL(...) \ template <class T> \ decltype(auto) operator()(T&& self) \ ___PRO_DIRECT_FUNC_IMPL(__VA_ARGS__ std::forward<T>(self)) \ template <class T> \ decltype(auto) operator()(T&& self, int) \ ___PRO_DIRECT_FUNC_IMPL(std::forward<T>(self) __VA_ARGS__) #define ___PRO_LHS_BINARY_OP_DISPATCH_BODY_IMPL(...) \ template <class T, class Arg> \ decltype(auto) operator()(T&& self, Arg&& arg) \ ___PRO_DIRECT_FUNC_IMPL(std::forward<T>(self) __VA_ARGS__ \ std::forward<Arg>(arg)) #define ___PRO_LHS_ALL_OP_DISPATCH_BODY_IMPL(...) \ ___PRO_LHS_LEFT_OP_DISPATCH_BODY_IMPL(__VA_ARGS__) \ ___PRO_LHS_BINARY_OP_DISPATCH_BODY_IMPL(__VA_ARGS__) #define ___PRO_LHS_OP_DISPATCH_IMPL(TYPE, ...) \ template <> \ struct operator_dispatch<#__VA_ARGS__, false> { \ ___PRO_LHS_##TYPE##_OP_DISPATCH_BODY_IMPL(__VA_ARGS__) \ ___PRO_DEF_MEM_ACCESSOR_TEMPLATE(___PRO_DEF_LHS_##TYPE##_OP_ACCESSOR, \ operator __VA_ARGS__) \ }; #define ___PRO_DEF_RHS_OP_ACCESSOR(Q, NE, SELF, FW_SELF, ...) \ template <class F, class C, class R, class Arg> \ struct accessor<F, C, R(Arg) Q> { \ friend R __VA_ARGS__ (Arg arg, SELF) NE { \ return proxy_invoke<C>( \ access_proxy<F>(FW_SELF), std::forward<Arg>(arg)); \ } \ } #define ___PRO_RHS_OP_DISPATCH_IMPL(...) \ template <> \ struct operator_dispatch<#__VA_ARGS__, true> { \ template <class T, class Arg> \ decltype(auto) operator()(T&& self, Arg&& arg) \ ___PRO_DIRECT_FUNC_IMPL(std::forward<Arg>(arg) __VA_ARGS__ \ std::forward<T>(self)) \ ___PRO_DEF_FREE_ACCESSOR_TEMPLATE(___PRO_DEF_RHS_OP_ACCESSOR, \ operator __VA_ARGS__) \ }; #define ___PRO_EXTENDED_BINARY_OP_DISPATCH_IMPL(...) \ ___PRO_LHS_OP_DISPATCH_IMPL(ALL, __VA_ARGS__) \ ___PRO_RHS_OP_DISPATCH_IMPL(__VA_ARGS__) #define ___PRO_BINARY_OP_DISPATCH_IMPL(...) \ ___PRO_LHS_OP_DISPATCH_IMPL(BINARY, __VA_ARGS__) \ ___PRO_RHS_OP_DISPATCH_IMPL(__VA_ARGS__) #define ___PRO_DEF_LHS_ASSIGNMENT_OP_ACCESSOR(Q, SELF, ...) \ template <class F, class C, class R, class Arg> \ struct accessor<F, C, R(Arg) Q> { \ decltype(auto) __VA_ARGS__ (Arg arg) Q { \ proxy_invoke<C>(access_proxy<F>(SELF), std::forward<Arg>(arg)); \ if constexpr (C::is_direct) { \ return access_proxy<F>(SELF); \ } else { \ return *access_proxy<F>(SELF); \ } \ } \ } #define ___PRO_DEF_RHS_ASSIGNMENT_OP_ACCESSOR(Q, NE, SELF, FW_SELF, ...) \ template <class F, class C, class R, class Arg> \ struct accessor<F, C, R(Arg&) Q> { \ friend Arg& __VA_ARGS__ (Arg& arg, SELF) NE { \ proxy_invoke<C>(access_proxy<F>(FW_SELF), arg); \ return arg; \ } \ } #define ___PRO_ASSIGNMENT_OP_DISPATCH_IMPL(...) \ template <> \ struct operator_dispatch<#__VA_ARGS__, false> { \ template <class T, class Arg> \ decltype(auto) operator()(T&& self, Arg&& arg) \ ___PRO_DIRECT_FUNC_IMPL(std::forward<T>(self) __VA_ARGS__ \ std::forward<Arg>(arg)) \ ___PRO_DEF_MEM_ACCESSOR_TEMPLATE(___PRO_DEF_LHS_ASSIGNMENT_OP_ACCESSOR, \ operator __VA_ARGS__) \ }; \ template <> \ struct operator_dispatch<#__VA_ARGS__, true> { \ template <class T, class Arg> \ decltype(auto) operator()(T&& self, Arg&& arg) \ ___PRO_DIRECT_FUNC_IMPL(std::forward<Arg>(arg) __VA_ARGS__ \ std::forward<T>(self)) \ ___PRO_DEF_FREE_ACCESSOR_TEMPLATE(___PRO_DEF_RHS_ASSIGNMENT_OP_ACCESSOR, \ operator __VA_ARGS__) \ }; ___PRO_EXTENDED_BINARY_OP_DISPATCH_IMPL(+) ___PRO_EXTENDED_BINARY_OP_DISPATCH_IMPL(-) ___PRO_EXTENDED_BINARY_OP_DISPATCH_IMPL(*) ___PRO_BINARY_OP_DISPATCH_IMPL(/) ___PRO_BINARY_OP_DISPATCH_IMPL(%) ___PRO_LHS_OP_DISPATCH_IMPL(UNARY, ++) ___PRO_LHS_OP_DISPATCH_IMPL(UNARY, --) ___PRO_BINARY_OP_DISPATCH_IMPL(==) ___PRO_BINARY_OP_DISPATCH_IMPL(!=) ___PRO_BINARY_OP_DISPATCH_IMPL(>) ___PRO_BINARY_OP_DISPATCH_IMPL(<) ___PRO_BINARY_OP_DISPATCH_IMPL(>=) ___PRO_BINARY_OP_DISPATCH_IMPL(<=) ___PRO_BINARY_OP_DISPATCH_IMPL(<=>) ___PRO_LHS_OP_DISPATCH_IMPL(LEFT, !) ___PRO_BINARY_OP_DISPATCH_IMPL(&&) ___PRO_BINARY_OP_DISPATCH_IMPL(||) ___PRO_LHS_OP_DISPATCH_IMPL(LEFT, ~) ___PRO_EXTENDED_BINARY_OP_DISPATCH_IMPL(&) ___PRO_BINARY_OP_DISPATCH_IMPL(|) ___PRO_BINARY_OP_DISPATCH_IMPL(^) ___PRO_BINARY_OP_DISPATCH_IMPL(<<) ___PRO_BINARY_OP_DISPATCH_IMPL(>>) ___PRO_ASSIGNMENT_OP_DISPATCH_IMPL(+=) ___PRO_ASSIGNMENT_OP_DISPATCH_IMPL(-=) ___PRO_ASSIGNMENT_OP_DISPATCH_IMPL(*=) ___PRO_ASSIGNMENT_OP_DISPATCH_IMPL(/=) ___PRO_ASSIGNMENT_OP_DISPATCH_IMPL(&=) ___PRO_ASSIGNMENT_OP_DISPATCH_IMPL(|=) ___PRO_ASSIGNMENT_OP_DISPATCH_IMPL(^=) ___PRO_ASSIGNMENT_OP_DISPATCH_IMPL(<<=) ___PRO_ASSIGNMENT_OP_DISPATCH_IMPL(>>=) ___PRO_BINARY_OP_DISPATCH_IMPL(,) ___PRO_BINARY_OP_DISPATCH_IMPL(->*) template <> struct operator_dispatch<"()", false> { template <class T, class... Args> decltype(auto) operator()(T&& self, Args&&... args) ___PRO_DIRECT_FUNC_IMPL( std::forward<T>(self)(std::forward<Args>(args)...)) ___PRO_DEF_MEM_ACCESSOR_TEMPLATE(___PRO_DEF_LHS_ANY_OP_ACCESSOR, operator()) }; template <> struct operator_dispatch<"[]", false> { #if defined(__cpp_multidimensional_subscript) && __cpp_multidimensional_subscript >= 202110L template <class T, class... Args> decltype(auto) operator()(T&& self, Args&&... args) ___PRO_DIRECT_FUNC_IMPL( std::forward<T>(self)[std::forward<Args>(args)...]) #else template <class T, class Arg> decltype(auto) operator()(T&& self, Arg&& arg) ___PRO_DIRECT_FUNC_IMPL(std::forward<T>(self)[std::forward<Arg>(arg)]) #endif // defined(__cpp_multidimensional_subscript) && __cpp_multidimensional_subscript >= 202110L ___PRO_DEF_MEM_ACCESSOR_TEMPLATE(___PRO_DEF_LHS_ANY_OP_ACCESSOR, operator[]) }; #undef ___PRO_ASSIGNMENT_OP_DISPATCH_IMPL #undef ___PRO_DEF_RHS_ASSIGNMENT_OP_ACCESSOR #undef ___PRO_DEF_LHS_ASSIGNMENT_OP_ACCESSOR #undef ___PRO_BINARY_OP_DISPATCH_IMPL #undef ___PRO_EXTENDED_BINARY_OP_DISPATCH_IMPL #undef ___PRO_RHS_OP_DISPATCH_IMPL #undef ___PRO_DEF_RHS_OP_ACCESSOR #undef ___PRO_LHS_OP_DISPATCH_IMPL #undef ___PRO_LHS_ALL_OP_DISPATCH_BODY_IMPL #undef ___PRO_LHS_BINARY_OP_DISPATCH_BODY_IMPL #undef ___PRO_LHS_UNARY_OP_DISPATCH_BODY_IMPL #undef ___PRO_LHS_LEFT_OP_DISPATCH_BODY_IMPL #undef ___PRO_DEF_LHS_ALL_OP_ACCESSOR #undef ___PRO_DEF_LHS_BINARY_OP_ACCESSOR #undef ___PRO_DEF_LHS_UNARY_OP_ACCESSOR #undef ___PRO_DEF_LHS_ANY_OP_ACCESSOR #undef ___PRO_DEF_LHS_LEFT_OP_ACCESSOR #define ___PRO_DEF_CONVERSION_ACCESSOR(Q, SELF, ...) \ template <class F, class C> \ struct accessor<F, C, T() Q> { \ explicit(Expl) __VA_ARGS__ () Q \ { return proxy_invoke<C>(access_proxy<F>(SELF)); } \ } template <class T, bool Expl = true> struct conversion_dispatch { template <class U> T operator()(U&& value) noexcept(std::conditional_t<Expl, std::is_nothrow_constructible<T, U>, std::is_nothrow_convertible<U, T>>::value) requires(std::conditional_t<Expl, std::is_constructible<T, U>, std::is_convertible<U, T>>::value) { return static_cast<T>(std::forward<U>(value)); } ___PRO_DEF_MEM_ACCESSOR_TEMPLATE(___PRO_DEF_CONVERSION_ACCESSOR, operator T) }; #undef ___PRO_DEF_CONVERSION_ACCESSOR #define ___PRO_EXPAND_IMPL(__X) __X #define ___PRO_EXPAND_MACRO_IMPL( \ __MACRO, __1, __2, __3, __NAME, ...) \ __MACRO##_##__NAME #define ___PRO_EXPAND_MACRO(__MACRO, ...) \ ___PRO_EXPAND_IMPL(___PRO_EXPAND_MACRO_IMPL( \ __MACRO, __VA_ARGS__, 3, 2)(__VA_ARGS__)) #define ___PRO_DEF_MEM_ACCESSOR(__Q, __SELF, ...) \ template <class __F, class __C, class __R, class... __Args> \ struct accessor<__F, __C, __R(__Args...) __Q> { \ __R __VA_ARGS__ (__Args... __args) __Q { \ return ::pro::proxy_invoke<__C>(::pro::access_proxy<__F>(__SELF), \ ::std::forward<__Args>(__args)...); \ } \ } #define ___PRO_DEF_MEM_DISPATCH_IMPL(__NAME, __FUNC, __FNAME) \ struct __NAME { \ template <class __T, class... __Args> \ decltype(auto) operator()(__T&& __self, __Args&&... __args) \ ___PRO_DIRECT_FUNC_IMPL(::std::forward<__T>(__self) \ .__FUNC(::std::forward<__Args>(__args)...)) \ ___PRO_DEF_MEM_ACCESSOR_TEMPLATE(___PRO_DEF_MEM_ACCESSOR, __FNAME) \ } #define ___PRO_DEF_MEM_DISPATCH_2(__NAME, __FUNC) \ ___PRO_DEF_MEM_DISPATCH_IMPL(__NAME, __FUNC, __FUNC) #define ___PRO_DEF_MEM_DISPATCH_3(__NAME, __FUNC, __FNAME) \ ___PRO_DEF_MEM_DISPATCH_IMPL(__NAME, __FUNC, __FNAME) #define PRO_DEF_MEM_DISPATCH(__NAME, ...) \ ___PRO_EXPAND_MACRO(___PRO_DEF_MEM_DISPATCH, __NAME, __VA_ARGS__) #define ___PRO_DEF_FREE_ACCESSOR(__Q, __NE, __SELF, __FW_SELF, ...) \ template <class __F, class __C, class __R, class... __Args> \ struct accessor<__F, __C, __R(__Args...) __Q> { \ friend __R __VA_ARGS__ (__SELF, __Args... __args) __NE { \ return ::pro::proxy_invoke<__C>(::pro::access_proxy<__F>(__FW_SELF), \ ::std::forward<__Args>(__args)...); \ } \ } #define ___PRO_DEF_FREE_DISPATCH_IMPL(__NAME, __FUNC, __FNAME) \ struct __NAME { \ template <class __T, class... __Args> \ decltype(auto) operator()(__T&& __self, __Args&&... __args) \ ___PRO_DIRECT_FUNC_IMPL(__FUNC(::std::forward<__T>(__self), \ ::std::forward<__Args>(__args)...)) \ ___PRO_DEF_FREE_ACCESSOR_TEMPLATE(___PRO_DEF_FREE_ACCESSOR, __FNAME) \ } #define ___PRO_DEF_FREE_DISPATCH_2(__NAME, __FUNC) \ ___PRO_DEF_FREE_DISPATCH_IMPL(__NAME, __FUNC, __FUNC) #define ___PRO_DEF_FREE_DISPATCH_3(__NAME, __FUNC, __FNAME) \ ___PRO_DEF_FREE_DISPATCH_IMPL(__NAME, __FUNC, __FNAME) #define PRO_DEF_FREE_DISPATCH(__NAME, ...) \ ___PRO_EXPAND_MACRO(___PRO_DEF_FREE_DISPATCH, __NAME, __VA_ARGS__) #define PRO_DEF_WEAK_DISPATCH(__NAME, __D, __FUNC) \ struct __NAME : __D { \ using __D::operator(); \ template <class... __Args> \ decltype(auto) operator()(::std::nullptr_t, __Args&&... __args) \ ___PRO_DIRECT_FUNC_IMPL(__FUNC(::std::forward<__Args>(__args)...)) \ } } // namespace pro #undef ___PRO_NO_UNIQUE_ADDRESS_ATTRIBUTE #endif // _MSFT_PROXY_ #include <iostream> #include <map> #include <memory> #include <string> #include <vector> PRO_DEF_MEM_DISPATCH(MemAt, at); struct Dictionary : pro::facade_builder ::add_convention<MemAt, std::string(int) const, std::string&(int)> ::add_convention<MemAt, std::string&(int)> ::build {}; void PrintDictionary(pro::proxy< Dictionary> dictionary) { // <-- Problem: only const access needed: how to specify? std::cout << dictionary->at(1) << "\n"; } void ModifyDictionary(pro::proxy<Dictionary> dictionary) { dictionary->at(1) = dictionary->at(1) + "XXX"; } int main() { const std::map<int, std::string> container1_const{{1, "hello"}}; std::map<int, std::string> container1 = container1_const; auto container2 = std::make_shared<std::vector<std::string>>(); container2->push_back("hello"); container2->push_back("world"); //PrintDictionary(&container1_const); <-- does not 'work', because is const ... PrintDictionary(&container1); PrintDictionary(container2); ModifyDictionary(&container1); ModifyDictionary(container2); PrintDictionary(&container1); PrintDictionary(container2); }
Become a Patron
Sponsor on GitHub
Donate via PayPal
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
About the author
Statistics
Changelog
Version tree