2
0
mirror of https://github.com/boostorg/compat.git synced 2026-01-20 16:32:23 +00:00

38 Commits

Author SHA1 Message Date
Peter Dimov
889d2608e6 Add VERBATIM to add_custom_target 2024-08-20 21:06:26 +03:00
Peter Dimov
787a5dd4d1 Update build.jam 2024-08-20 20:56:20 +03:00
Rene Rivera
a6520ef2e1 Sync from upstream. 2024-07-25 17:20:02 -05:00
Rene Rivera
0d2593326f Move inter-lib dependencies to a project variable and into the build targets. 2024-07-23 22:34:24 -05:00
Peter Dimov
4abae7082a Update ci.yml 2024-07-22 02:15:35 +03:00
Peter Dimov
d802b97ba8 Update .drone.jsonnet 2024-07-22 02:03:00 +03:00
Rene Rivera
e6d2faa267 Sync from upstream. 2024-07-12 08:55:45 -05:00
Peter Dimov
9244cd17b9 Merge pull request #11 from cmazakas/feature/function-ref-cpp17
implement pointer-to-member function_ref overloads
2024-06-22 20:09:56 +03:00
Christian Mazakas
37dbb81cce add workaround for clang-7 2024-06-21 07:57:36 -07:00
Christian Mazakas
8ed23dd6a7 implement pointer-to-member function_ref overloads 2024-06-21 07:57:36 -07:00
Peter Dimov
915a207fc9 Merge pull request #12 from cmazakas/fix/obj-tests
fix function_ref Callable constructor
2024-06-21 05:30:24 +03:00
Christian Mazakas
2a5e8031f8 fix erroneous handling of const types in function_ref callable constructor 2024-06-20 11:28:10 -07:00
Christian Mazakas
b9f5082f6e expand fn object function_ref tests 2024-06-20 11:28:10 -07:00
Peter Dimov
6a0f933b2e Update BOOST_MSVC workarounds for msvc-14.3 19.40 2024-06-19 03:38:32 +03:00
Peter Dimov
ef0f49933b Update ci.yml 2024-06-19 03:36:09 +03:00
Rene Rivera
438e0fbbf3 Bump B2 require to 5.2 2024-06-14 11:33:55 -05:00
Rene Rivera
df5cd71735 Add requires-b2 check to top-level build file. 2024-05-05 09:00:00 -05:00
Rene Rivera
6f8c2fe8c1 Add missing import-search for cconfig/predef checks. 2024-05-04 23:28:15 -05:00
Rene Rivera
e5f0043abc Sync from upstream. 2024-04-28 20:36:12 -05:00
Peter Dimov
fb5f95b3b2 Remove unnecessary GCC jobs from Drone 2024-04-28 20:57:41 +03:00
Peter Dimov
cc45f3198a Disable -Warray-bounds on GCC when sanitization is on 2024-04-28 20:12:14 +03:00
Peter Dimov
ef87b7c225 Add Drone support 2024-04-28 19:12:02 +03:00
Peter Dimov
257ce0b4bd Update ci.yml 2024-04-28 13:48:18 +03:00
Peter Dimov
ea462a4363 Update revision history 2024-04-28 13:45:11 +03:00
Rene Rivera
d5cf9802bd Add new lib dependencies. 2024-04-25 22:12:11 -05:00
Rene Rivera
28496a6a01 Sync from upstream. 2024-04-20 15:34:30 -05:00
Peter Dimov
09dd50c8db Merge pull request #10 from cmazakas/feature/function-ref
add c++11 version of `function_ref`
2024-04-17 20:49:09 +03:00
Christian Mazakas
f969df9b2a Add workaround for msvc-14.1 2024-04-17 10:12:05 -07:00
Christian Mazakas
74d9d80471 Add initial function_ref docs 2024-04-17 09:40:34 -07:00
Christian Mazakas
26e3edd0af Add initial draft of function_ref 2024-04-17 09:40:34 -07:00
Christian Mazakas
09d1a51778 Add gitignore 2024-04-17 09:40:34 -07:00
Peter Dimov
f0aeb3ba95 Revert "Update doc/Jamfile"
This reverts commit 0afd51fcd3.
2024-04-16 22:37:08 +03:00
Peter Dimov
0afd51fcd3 Update doc/Jamfile 2024-04-16 22:16:08 +03:00
Rene Rivera
ed8837a4ff Sync from upstream. 2024-04-10 07:58:31 -05:00
Peter Dimov
54c72a5033 Update documentation 2024-04-06 22:56:05 +03:00
Rene Rivera
7fc7795d6b Switch to library requirements instead of source. As source puts extra source in install targets. 2024-03-29 21:15:58 -05:00
Rene Rivera
0598dd0688 Sync from upstream. 2024-03-23 07:58:05 -05:00
Rene Rivera
c511487e78 Make the library modular usable. 2024-03-11 08:27:02 -05:00
25 changed files with 2149 additions and 26 deletions

275
.drone.jsonnet Normal file
View File

@@ -0,0 +1,275 @@
# Copyright 2022 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
local library = "compat";
local triggers =
{
branch: [ "master", "develop", "feature/*" ]
};
local ubsan = { UBSAN: '1', UBSAN_OPTIONS: 'print_stacktrace=1' };
local asan = { ASAN: '1' };
local linux_pipeline(name, image, environment, packages = "", sources = [], arch = "amd64") =
{
name: name,
kind: "pipeline",
type: "docker",
trigger: triggers,
platform:
{
os: "linux",
arch: arch
},
steps:
[
{
name: "everything",
image: image,
environment: environment,
commands:
[
'set -e',
'wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -',
] +
(if sources != [] then [ ('apt-add-repository "' + source + '"') for source in sources ] else []) +
(if packages != "" then [ 'apt-get update', 'apt-get -y install ' + packages ] else []) +
[
'export LIBRARY=' + library,
'./.drone/drone.sh',
]
}
]
};
local macos_pipeline(name, environment, xcode_version = "12.2", osx_version = "catalina", arch = "amd64") =
{
name: name,
kind: "pipeline",
type: "exec",
trigger: triggers,
platform: {
"os": "darwin",
"arch": arch
},
node: {
"os": osx_version
},
steps: [
{
name: "everything",
environment: environment + { "DEVELOPER_DIR": "/Applications/Xcode-" + xcode_version + ".app/Contents/Developer" },
commands:
[
'export LIBRARY=' + library,
'./.drone/drone.sh',
]
}
]
};
local windows_pipeline(name, image, environment, arch = "amd64") =
{
name: name,
kind: "pipeline",
type: "docker",
trigger: triggers,
platform:
{
os: "windows",
arch: arch
},
"steps":
[
{
name: "everything",
image: image,
environment: environment,
commands:
[
'cmd /C .drone\\\\drone.bat ' + library,
]
}
]
};
[
linux_pipeline(
"Linux 16.04 GCC 4.8 32/64",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-4.8', CXXSTD: '11', ADDRMD: '32,64' },
"g++-4.8-multilib",
),
linux_pipeline(
"Linux 16.04 GCC 4.9 32/64",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-4.9', CXXSTD: '11', ADDRMD: '32,64' },
"g++-4.9-multilib",
),
linux_pipeline(
"Linux 16.04 GCC 5* 32/64",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14', ADDRMD: '32,64' },
),
linux_pipeline(
"Linux 18.04 GCC 7* 32/64",
"cppalliance/droneubuntu1804:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17', ADDRMD: '32,64' },
),
linux_pipeline(
"Linux 20.04 GCC 9 ARM64 UBSAN",
"cppalliance/droneubuntu2004:multiarch",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a' } + ubsan,
arch="arm64",
),
linux_pipeline(
"Linux 20.04 GCC 9 ARM64 ASAN",
"cppalliance/droneubuntu2004:multiarch",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a' } + asan,
arch="arm64",
),
linux_pipeline(
"Linux 20.04 GCC 9 S390x UBSAN",
"cppalliance/droneubuntu2004:multiarch",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a' } + ubsan,
arch="s390x",
),
linux_pipeline(
"Linux 22.04 GCC 12 32/64",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '11,14,17,20', ADDRMD: '32,64' },
"g++-12-multilib",
),
linux_pipeline(
"Linux 23.04 GCC 13 32/64",
"cppalliance/droneubuntu2304:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '11,14,17,20,2b', ADDRMD: '32,64' },
"g++-13-multilib",
),
linux_pipeline(
"Linux 24.04 GCC 14 32 ASAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b', ADDRMD: '32' } + asan,
"g++-14-multilib",
),
linux_pipeline(
"Linux 24.04 GCC 14 64 ASAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b', ADDRMD: '64' } + asan,
"g++-14-multilib",
),
linux_pipeline(
"Linux 24.04 GCC 14 32 UBSAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b', ADDRMD: '32' } + ubsan,
"g++-14-multilib",
),
linux_pipeline(
"Linux 24.04 GCC 14 64 UBSAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b', ADDRMD: '64' } + ubsan,
"g++-14-multilib",
),
linux_pipeline(
"Linux 22.04 Clang 15",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '11,14,17,20,2b' },
"clang-15",
),
linux_pipeline(
"Linux 23.04 Clang 16",
"cppalliance/droneubuntu2304:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-16', CXXSTD: '11,14,17,20,2b' },
"clang-16",
),
linux_pipeline(
"Linux 23.10 Clang 17 UBSAN",
"cppalliance/droneubuntu2310:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '11,14,17,20,2b' } + ubsan,
"clang-17",
),
linux_pipeline(
"Linux 23.10 Clang 17 ASAN",
"cppalliance/droneubuntu2310:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '11,14,17,20,2b' } + asan,
"clang-17",
),
linux_pipeline(
"Linux 24.04 Clang 18 UBSAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '11,14,17,20,2b' } + ubsan,
"clang-18",
),
linux_pipeline(
"Linux 24.04 Clang 18 ASAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '11,14,17,20,2b' } + asan,
"clang-18",
),
macos_pipeline(
"MacOS 10.15 Xcode 12.2 UBSAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,1z' } + ubsan,
),
macos_pipeline(
"MacOS 10.15 Xcode 12.2 ASAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,1z' } + asan,
),
macos_pipeline(
"MacOS 12.4 Xcode 13.4.1 UBSAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,17,20,2b' } + ubsan,
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
),
macos_pipeline(
"MacOS 12.4 Xcode 13.4.1 ASAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,17,20,2b' } + asan,
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
),
windows_pipeline(
"Windows VS2015 msvc-14.0",
"cppalliance/dronevs2015",
{ TOOLSET: 'msvc-14.0', CXXSTD: '14,latest', B2_DONT_EMBED_MANIFEST: '1' },
),
windows_pipeline(
"Windows VS2017 msvc-14.1",
"cppalliance/dronevs2017",
{ TOOLSET: 'msvc-14.1', CXXSTD: '14,17,latest' },
),
windows_pipeline(
"Windows VS2019 msvc-14.2",
"cppalliance/dronevs2019",
{ TOOLSET: 'msvc-14.2', CXXSTD: '14,17,20,latest' },
),
windows_pipeline(
"Windows VS2022 msvc-14.3",
"cppalliance/dronevs2022:1",
{ TOOLSET: 'msvc-14.3', CXXSTD: '14,17,20,latest' },
),
]

25
.drone/drone.bat Normal file
View File

@@ -0,0 +1,25 @@
@REM Copyright 2022 Peter Dimov
@REM Distributed under the Boost Software License, Version 1.0.
@REM https://www.boost.org/LICENSE_1_0.txt
@ECHO ON
set LIBRARY=%1
set DRONE_BUILD_DIR=%CD%
echo %DRONE_STAGE_MACHINE%
set BOOST_BRANCH=develop
if "%DRONE_BRANCH%" == "master" set BOOST_BRANCH=master
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
git submodule update --init tools/boostdep
xcopy /s /e /q %DRONE_BUILD_DIR% libs\%LIBRARY%\
python tools/boostdep/depinst/depinst.py %LIBRARY%
cmd /c bootstrap
b2 -d0 headers
if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
b2 -j3 libs/%LIBRARY%/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker

31
.drone/drone.sh Executable file
View File

@@ -0,0 +1,31 @@
#!/bin/bash
# Copyright 2022 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
set -ex
export PATH=~/.local/bin:/usr/local/bin:$PATH
uname -a
echo $DRONE_STAGE_MACHINE
command -v lscpu && lscpu
DRONE_BUILD_DIR=$(pwd)
BOOST_BRANCH=develop
if [ "$DRONE_BRANCH" = "master" ]; then BOOST_BRANCH=master; fi
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
git submodule update --init tools/boostdep
cp -r $DRONE_BUILD_DIR/* libs/$LIBRARY
python tools/boostdep/depinst/depinst.py $LIBRARY
CXXFLAGS= ./bootstrap.sh
./b2 -d0 headers
echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam
./b2 -j2 libs/$LIBRARY/test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release \
${ADDRMD:+address-model=$ADDRMD} ${CXXFLAGS:+cxxflags=$CXXFLAGS} ${LINKFLAGS:+linkflags=$LINKFLAGS} \
${UBSAN:+undefined-sanitizer=norecover debug-symbols=on} ${ASAN:+address-sanitizer=norecover debug-symbols=on}

View File

@@ -19,23 +19,23 @@ jobs:
include:
- toolset: gcc-4.8
cxxstd: "03,11"
os: ubuntu-latest
container: ubuntu:18.04
os: ubuntu-latest
install: g++-4.8
- toolset: gcc-4.9
cxxstd: "03,11"
os: ubuntu-latest
container: ubuntu:16.04
os: ubuntu-latest
install: g++-4.9
- toolset: gcc-5
cxxstd: "03,11,14,1z"
os: ubuntu-latest
container: ubuntu:18.04
os: ubuntu-latest
install: g++-5
- toolset: gcc-6
cxxstd: "03,11,14,1z"
os: ubuntu-latest
container: ubuntu:18.04
os: ubuntu-latest
install: g++-6
- toolset: gcc-7
cxxstd: "03,11,14,17"
@@ -54,34 +54,38 @@ jobs:
install: g++-10
- toolset: gcc-11
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
install: g++-11
os: ubuntu-22.04
- toolset: gcc-12
cxxstd: "03,11,14,17,20,2b"
os: ubuntu-22.04
install: g++-12
- toolset: gcc-13
cxxstd: "03,11,14,17,20,2b"
os: ubuntu-latest
container: ubuntu:23.04
os: ubuntu-latest
install: g++-13
- toolset: gcc-14
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:24.04
os: ubuntu-latest
install: g++-14
- toolset: clang
compiler: clang++-3.9
cxxstd: "03,11,14"
os: ubuntu-latest
container: ubuntu:18.04
os: ubuntu-latest
install: clang-3.9
- toolset: clang
compiler: clang++-4.0
cxxstd: "03,11,14"
os: ubuntu-latest
container: ubuntu:18.04
os: ubuntu-latest
install: clang-4.0
- toolset: clang
compiler: clang++-5.0
cxxstd: "03,11,14,1z"
os: ubuntu-latest
container: ubuntu:18.04
os: ubuntu-latest
install: clang-5.0
- toolset: clang
compiler: clang++-6.0
@@ -149,14 +153,20 @@ jobs:
os: ubuntu-latest
install: clang-17
- toolset: clang
cxxstd: "03,11,14,17,2a"
os: macos-11
compiler: clang++-18
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:24.04
os: ubuntu-latest
install: clang-18
- toolset: clang
cxxstd: "03,11,14,17,20,2b"
os: macos-12
- toolset: clang
cxxstd: "03,11,14,17,20,2b"
os: macos-13
- toolset: clang
cxxstd: "03,11,14,17,20,2b"
os: macos-14
runs-on: ${{matrix.os}}
container: ${{matrix.container}}
@@ -166,6 +176,10 @@ jobs:
shell: bash
steps:
- name: Enable Node 16
run: |
echo "ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true" >> $GITHUB_ENV
- uses: actions/checkout@v3
- name: Setup container environment
@@ -279,9 +293,9 @@ jobs:
include:
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-11
- os: macos-12
- os: macos-13
- os: macos-14
runs-on: ${{matrix.os}}
@@ -328,9 +342,9 @@ jobs:
include:
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-11
- os: macos-12
- os: macos-13
- os: macos-14
runs-on: ${{matrix.os}}
@@ -387,9 +401,9 @@ jobs:
include:
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-11
- os: macos-12
- os: macos-13
- os: macos-14
runs-on: ${{matrix.os}}

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
/__build__
/toolchain.cmake
/compile_commands.json
/.cache
/.vscode

22
build.jam Normal file
View File

@@ -0,0 +1,22 @@
# Copyright 2024 René Ferdinand Rivera Morell
# Copyright 2024 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
require-b2 5.2 ;
constant boost_dependencies :
/boost/assert//boost_assert
/boost/config//boost_config
/boost/throw_exception//boost_throw_exception
;
project /boost/compat ;
explicit
[ alias boost_compat : : : : <include>include <library>$(boost_dependencies) ]
[ alias all : boost_compat test ]
;
call-if : boost-library compat
;

View File

@@ -11,6 +11,7 @@ https://www.boost.org/LICENSE_1_0.txt
## Changes in 1.86.0
* Added `bind_front.hpp`, `bind_back.hpp`, `invoke.hpp`, `mem_fn.hpp`, `integer_sequence.hpp` and `type_traits.hpp`.
* Added `function_ref.hpp`.
## Changes in 1.83.0

View File

@@ -0,0 +1,200 @@
////
Copyright 2024 Christian Mazakas
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
[#function_ref]
# <boost/compat/function_ref.hpp>
:idprefix: ref_function_ref_
## Description
The header `<boost/compat/function_ref.hpp>` implements the {cpp}26 class
`std::function_ref`.
`function_ref` is a lightweight polymorphic function wrapper that only stores a pointer to the supplied https://en.cppreference.com/w/cpp/named_req/Callable[Callable] object and a pointer to an unspecified function, meaning it does not participate in ownership of the Callable and does not allocate. All specializations of `function_ref` satisfy https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable[TriviallyCopyable].
`function_ref` supports every combination of `const` and `noexcept` and is useful for writing higher-order functions as
it can avoid a template parameter or an allocation (as `std::function` is known for).
## Example
```cpp
int add(int x, int y) noexcept { return x * 10 + y; }
auto add2 = [](int x, int y) { return x * 100 + y; };
std::vector<boost::compat::function_ref<int(int, int)>> fns;
fns.push_back({add});
fns.push_back({add2});
for (auto fn : fns) {
std::cout << fn(1, 2) << std::endl;
}
```
## Synopsis
```cpp
namespace boost
{
namespace compat
{
template <class... S>
struct function_ref;
// cv is either `const` or empty
// noex is either `true` or `false`
template<class R, class... ArgTypes>
class function_ref<R(ArgTypes...) cv noexcept(noex)> {
public:
template<class F> function_ref(F*) noexcept;
template<class F> function_ref(F&&) noexcept;
template<auto f> function_ref(nontype_t<f>) noexcept;
template<auto f, class U> function_ref(nontype_t<f>, U&&) noexcept;
template<auto f, class T> function_ref(nontype_t<f>, cv T*) noexcept;
function_ref(const function_ref&) noexcept = default;
function_ref& operator=(const function_ref&) noexcept = default;
template<class T> function_ref& operator=(T) = delete;
R operator()(ArgTypes...) const noexcept(noex);
};
} // namespace compat
} // namespace boost
```
## Constructors
### Function Pointer Constructor
```cpp
template<class F> function_ref(F* fn) noexcept;
```
[horizontal]
Preconditions:: `fn` != `nullptr`.
Effects::
Constructs a `function_ref` which uses the supplied function pointer as its Callable. +
+
Calling the `function_ref` is expression-equivalent to `invoke_r<R>(f, call-args...)`.
### Object Constructor
```cpp
template<class F> function_ref(F&& fn) noexcept;
```
[horizontal]
Effects:;; Constructs a `function_ref` that stores the address of the supplied Callable object `fn`. This overload only
participates in resolution when `fn` is not a pointer-to-member or pointer-to-member-function. +
+
Calling the `function_ref` is expression-equivalent to: + `invoke_r<R>(static_cast<cv T&>(f), call-args...)`.
### Pointer to Member Function Constructor
```cpp
template<auto f> function_ref(nontype_t<f>) noexcept;
```
[horizontal]
Effects:;; Constructs a `function_ref` using the supplied pointer to member function. This overload only participates
in resolution when `f` is a pointer to member or pointer to member function. +
+
Calling the `function_ref` is express-equivalent to: `invoke_r<R>(f, class-args)`.
Example:;;
+
--
```cpp
struct point { int x = 1, y = 2; };
point p;
compat::function_ref<int(point const&)> f(compat::nontype_t<&point::x>{});
BOOST_TEST_EQ(f(p), 1);
```
--
### Bound Object Constructor
```cpp
template<auto f, class U> function_ref(nontype_t<f>, U&&) noexcept;
```
[horizontal]
Effects:;; Constructs a `function_ref` using the supplied pointer to member or pointer to member function and a reference
to an object to bind it to. +
+
This overload only participates in resolution if `is_rvalue_reference_v<U&&>` is false.
Example:;;
+
--
```cpp
struct point { int x = 1, y = 2; };
point p;
compat::function_ref<int()> f(compat::nontype_t<&point::x>{}, p);
BOOST_TEST_EQ(f(), 1);
```
--
### Bound Pointer Constructor
```cpp
template<auto f, class T> function_ref(nontype_t<f>, cv T*) noexcept;
```
[horizontal]
Effects:;; Constructs a `function_ref` using the supplied pointer to member or pointer to member function and a pointer
to an object.
Example:;;
+
--
```cpp
struct point { int x = 1, y = 2; };
point p;
compat::function_ref<int()> f(compat::nontype_t<&point::x>{}, &p);
BOOST_TEST_EQ(f(), 1);
```
--
### Copy Constructor
```cpp
function_ref(const function_ref&) noexcept = default;
```
[horizontal]
Effects:;; `function_ref` is a TriviallyCopyable type.
## Member Functions
### call operator
```cpp
R operator()(ArgTypes...) const noexcept(noex);
```
[horizontal]
Effects:;; Invokes the underlying Callable object by forwarding the supplied arguments.
## Assignment
### Copy Assignment
```cpp
function_ref& operator=(const function_ref&) noexcept = default;
template<class T> function_ref& operator=(T) = delete;
```
[horizontal]
Effects:;; `operator=(T)` participates in overload resolution if:
* `T` is not the same as `function_ref`
* `is_pointer_v<T>` is `false`.

View File

@@ -11,14 +11,17 @@ https://www.boost.org/LICENSE_1_0.txt
## Description
The header `<boost/compat/invoke.hpp>` implements the {cpp}17 function
`std::invoke` and the associated utilities `invoke_result_t`, `is_invocable`,
and `is_nothrow_invocable`.
`std::invoke`, the {cpp}23 function `std::invoke_r`, and the associated
utilities `invoke_result_t`, `is_invocable`, `is_invocable_r`,
`is_nothrow_invocable`, and `is_nothrow_invocable_r`.
`invoke(f, a...)` generally returns `f(a...)`, but when `f` is a pointer to
member, it invokes it as if by returning `mem_fn(f)(a...)`. This allows
functions, function objects, and pointers to members to be treated uniformly
by components such as `bind_front`.
`invoke_r<R>(f, a...)` returns `invoke(f, a...)`, converted to `R`.
## Example
```
@@ -50,6 +53,12 @@ template<class F, class... A> struct is_invocable;
template<class F, class... A> struct is_nothrow_invocable;
template<class R, class F, class... A> R invoke_r(F&& f, A&&... a);
template<class R, class F, class... A> struct is_invocable_r;
template<class R, class F, class... A> struct is_nothrow_invocable_r;
} // namespace compat
} // namespace boost
```
@@ -57,7 +66,7 @@ template<class F, class... A> struct is_nothrow_invocable;
## invoke
```
template<class F, class... A> auto invoke(F&& f, A&&... a) noexcept(/*...*/);
template<class F, class... A> auto invoke(F&& f, A&&... a) noexcept(/*...*/) -> /*...*/;
```
[horizontal]
@@ -65,7 +74,7 @@ Returns:;;
* `std::forward<F>(f)(std::forward<A>(a)...)`, when `f` is not a pointer to member;
* `mem_fn(f)(std::forward<A>(a)...)`, otherwise.
Constraints:;; the return expression must be valid.
Remarks:;; The `noexcept` clause is `noexcept(noexcept(r))`, where `r` is the return expression.
Remarks:;; The return type is `decltype(r)`, and the `noexcept` clause is `noexcept(noexcept(r))`, where `r` is the return expression.
## invoke_result_t
@@ -90,3 +99,32 @@ template<class F, class... A> struct is_nothrow_invocable: public /*...*/;
The base class of `is_nothrow_invocable<F, A...>` is `std::false_type` when `is_invocable<F, A...>::value` is `false`, `std::integral_constant<bool, noexcept(invoke(std::declval<F>(), std::declval<A>()...))>` otherwise.
## invoke_r
```
template<class R, class F, class... A> R invoke_r(F&& f, A&&... a) noexcept(/*...*/);
```
[horizontal]
Returns:;;
* `static_cast<R>(invoke(std::forward<F>(f), std::forward<A>(a)...))`, when `R` is (possibly cv-qualified) `void`;
* `invoke(std::forward<F>(f), std::forward<A>(a)...)`, implicitly converted to `R`, otherwise.
Constraints:;; `is_invocable<F, A...>::value` must be `true` and, if `R` is not cv `void`, `std::is_convertible<invoke_result_t<F, A...>, R>::value` must be `true`.
Remarks:;; The `noexcept` clause is `noexcept(noexcept(static_cast<R>(invoke(std::forward<F>(f), std::forward<A>(a)...))))`.
## is_invocable_r
```
template<class R, class F, class... A> struct is_invocable: public /*...*/;
```
The base class of `is_invocable_r<R, F, A...>` is `std::true_type` when `invoke_r<R>(std::declval<F>(), std::declval<A>()...)` is a valid expression, `std::false_type` otherwise.
## is_nothrow_invocable_r
```
template<class R, class F, class... A> struct is_nothrow_invocable: public /*...*/;
```
The base class of `is_nothrow_invocable<R, F, A...>` is `std::false_type` when `is_invocable_r<R, F, A...>::value` is `false`, `std::integral_constant<bool, noexcept(invoke_r<R>(std::declval<F>(), std::declval<A>()...))>` otherwise.

View File

@@ -6,6 +6,7 @@ https://www.boost.org/LICENSE_1_0.txt
include::bind_back.adoc[]
include::bind_front.adoc[]
include::function_ref.adoc[]
include::integer_sequence.adoc[]
include::invoke.adoc[]
include::latch.adoc[]

View File

@@ -0,0 +1,314 @@
#ifndef BOOST_COMPAT_FUNCTION_REF_HPP_INCLUDED
#define BOOST_COMPAT_FUNCTION_REF_HPP_INCLUDED
// Copyright 2024 Christian Mazakas.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/invoke.hpp>
#include <boost/compat/type_traits.hpp>
#include <type_traits>
#include <utility>
#if defined(__cpp_nontype_template_parameter_auto) && __cpp_nontype_template_parameter_auto >= 201606L
#define BOOST_COMPAT_HAS_AUTO_NTTP
#endif
namespace boost {
namespace compat {
template <class... S>
struct function_ref;
#if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
template <auto V>
struct nontype_t {
explicit nontype_t() = default;
};
#endif
namespace detail {
template <bool NoEx>
union thunk_storage {
void* pobj_;
void (*pfn_)() noexcept(NoEx);
};
template <bool NoEx, class Fp, class R, class... Args>
struct invoke_function_holder {
static R invoke_function(thunk_storage<NoEx> s, Args&&... args) noexcept(NoEx) {
auto f = reinterpret_cast<Fp>(s.pfn_);
return compat::invoke_r<R>(f, std::forward<Args>(args)...);
}
};
template <bool Const, bool NoEx, class F, class R, class... Args>
struct invoke_object_holder {
static R invoke_object(thunk_storage<NoEx> s, Args&&... args) noexcept(NoEx) {
using T = remove_reference_t<F>;
using cv_T = conditional_t<Const, add_const_t<T>, T>;
return compat::invoke_r<R>(*static_cast<cv_T*>(s.pobj_), std::forward<Args>(args)...);
}
};
#if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
template <auto f, bool Const, bool NoEx, class R, class... Args>
struct invoke_mem_fn_holder {
static R invoke_mem_fn(thunk_storage<NoEx> /* s */, Args&&... args) noexcept(NoEx) {
return compat::invoke_r<R>(f, std::forward<Args>(args)...);
}
};
template <auto f, class U, bool Const, bool NoEx, class R, class... Args>
struct invoke_target_mem_fn_holder {
static R invoke_mem_fn(thunk_storage<NoEx> s, Args&&... args) noexcept(NoEx) {
using T = remove_reference_t<U>;
using cv_T = conditional_t<Const, add_const_t<T>, T>;
return compat::invoke_r<R>(f, *static_cast<cv_T*>(s.pobj_), std::forward<Args>(args)...);
}
};
template <auto f, class T, bool Const, bool NoEx, class R, class... Args>
struct invoke_ptr_mem_fn_holder {
static R invoke_mem_fn(thunk_storage<NoEx> s, Args&&... args) noexcept(NoEx) {
using cv_T = conditional_t<Const, add_const_t<T>, T>;
return compat::invoke_r<R>(f, static_cast<cv_T*>(s.pobj_), std::forward<Args>(args)...);
}
};
#endif
template <bool Const, bool NoEx, class R, class... Args>
struct function_ref_base {
private:
thunk_storage<NoEx> thunk_ = nullptr;
R (*invoke_)(thunk_storage<NoEx>, Args&&...) noexcept(NoEx) = nullptr;
public:
struct fp_tag {};
struct obj_tag {};
struct mem_fn_tag {};
template <class F>
function_ref_base(fp_tag, F* fn) noexcept
: thunk_{}, invoke_(&invoke_function_holder<NoEx, F*, R, Args...>::invoke_function) {
thunk_.pfn_ = reinterpret_cast<decltype(thunk_.pfn_)>(fn);
}
template <class F>
function_ref_base(obj_tag, F&& fn) noexcept
: thunk_{}, invoke_(&invoke_object_holder<Const, NoEx, F, R, Args...>::invoke_object) {
thunk_.pobj_ = const_cast<void*>(static_cast<void const*>(std::addressof(fn)));
}
#if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
template <auto f, class F = decltype(f)>
function_ref_base(mem_fn_tag, nontype_t<f>)
: thunk_{}, invoke_(&invoke_mem_fn_holder<F{f}, Const, NoEx, R, Args...>::invoke_mem_fn) {
thunk_.pobj_ = nullptr;
}
template <auto f, class U, class F = decltype(f)>
function_ref_base(mem_fn_tag, nontype_t<f>, U&& obj)
: thunk_{}, invoke_(&invoke_target_mem_fn_holder<F{f}, U, Const, NoEx, R, Args...>::invoke_mem_fn) {
thunk_.pobj_ = const_cast<void*>(static_cast<void const*>(std::addressof(obj)));
}
template <auto f, class T, class F = decltype(f)>
function_ref_base(mem_fn_tag, nontype_t<f>, T* obj)
: thunk_{}, invoke_(&invoke_ptr_mem_fn_holder<F{f}, T, Const, NoEx, R, Args...>::invoke_mem_fn) {
thunk_.pobj_ = const_cast<void*>(static_cast<void const*>(obj));
}
#endif
function_ref_base(const function_ref_base&) noexcept = default;
function_ref_base& operator=(const function_ref_base&) noexcept = default;
R operator()(Args&&... args) const noexcept(NoEx) { return this->invoke_(thunk_, std::forward<Args>(args)...); }
};
} // namespace detail
template <class R, class... Args>
struct function_ref<R(Args...)> : public detail::function_ref_base<false, false, R, Args...> {
private:
using base_type = detail::function_ref_base<false, false, R, Args...>;
using typename base_type::fp_tag;
using typename base_type::mem_fn_tag;
using typename base_type::obj_tag;
template <class... T>
using is_invocable_using = boost::compat::is_invocable_r<R, T..., Args...>;
public:
template <class F, enable_if_t<std::is_function<F>::value && is_invocable_using<F>::value, int> = 0>
function_ref(F* fn) noexcept : base_type(fp_tag{}, fn) {}
template <class F, class T = remove_reference_t<F>,
enable_if_t<!std::is_same<remove_cvref_t<F>, function_ref>::value && !std::is_member_pointer<T>::value &&
is_invocable_using<T&>::value,
int> = 0>
function_ref(F&& fn) noexcept : base_type(obj_tag{}, fn) {}
#if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
template <auto f, class F = decltype(f), enable_if_t<is_invocable_using<F>::value, int> = 0>
function_ref(nontype_t<f> x) noexcept : base_type(mem_fn_tag{}, x) {}
template <auto f, class U, class T = remove_reference_t<U>, class F = decltype(f),
enable_if_t<!std::is_rvalue_reference_v<U&&> && is_invocable_using<F, T&>::value, int> = 0>
function_ref(nontype_t<f> x, U&& obj) noexcept : base_type(mem_fn_tag{}, x, std::forward<U>(obj)) {}
template <auto f, class T, class F = decltype(f), enable_if_t<is_invocable_using<F, T*>::value, int> = 0>
function_ref(nontype_t<f> x, T* obj) noexcept : base_type(mem_fn_tag{}, x, obj) {}
#endif
function_ref(const function_ref&) noexcept = default;
function_ref& operator=(const function_ref&) noexcept = default;
template <class T, enable_if_t<!std::is_same<T, function_ref>::value && !std::is_pointer<T>::value, int> = 0>
function_ref& operator=(T) = delete;
};
template <class R, class... Args>
struct function_ref<R(Args...) const> : public detail::function_ref_base<true, false, R, Args...> {
private:
using base_type = detail::function_ref_base<true, false, R, Args...>;
using typename base_type::fp_tag;
using typename base_type::mem_fn_tag;
using typename base_type::obj_tag;
template <class... T>
using is_invocable_using = boost::compat::is_invocable_r<R, T..., Args...>;
public:
template <class F, enable_if_t<std::is_function<F>::value && is_invocable_using<F>::value, int> = 0>
function_ref(F* fn) noexcept : base_type(fp_tag{}, fn) {}
template <class F, class T = remove_reference_t<F>,
enable_if_t<!std::is_same<remove_cvref_t<F>, function_ref>::value && !std::is_member_pointer<T>::value &&
is_invocable_using<T const&>::value,
int> = 0>
function_ref(F&& fn) noexcept : base_type(obj_tag{}, fn) {}
#if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
template <auto f, class F = decltype(f), enable_if_t<is_invocable_using<F>::value, int> = 0>
function_ref(nontype_t<f> x) noexcept : base_type(mem_fn_tag{}, x) {}
template <auto f, class U, class T = remove_reference_t<U>, class F = decltype(f),
enable_if_t<!std::is_rvalue_reference_v<U&&> && is_invocable_using<F, T const&>::value, int> = 0>
function_ref(nontype_t<f> x, U&& obj) noexcept : base_type(mem_fn_tag{}, x, std::forward<U>(obj)) {}
template <auto f, class T, class F = decltype(f), enable_if_t<is_invocable_using<F, T const*>::value, int> = 0>
function_ref(nontype_t<f> x, T const* obj) noexcept : base_type(mem_fn_tag{}, x, obj) {}
#endif
function_ref(const function_ref&) noexcept = default;
function_ref& operator=(const function_ref&) noexcept = default;
template <class T, enable_if_t<!std::is_same<T, function_ref>::value && !std::is_pointer<T>::value, int> = 0>
function_ref& operator=(T) = delete;
};
#if defined(__cpp_noexcept_function_type)
template <class R, class... Args>
struct function_ref<R(Args...) noexcept> : public detail::function_ref_base<false, true, R, Args...> {
private:
using base_type = detail::function_ref_base<false, true, R, Args...>;
using typename base_type::fp_tag;
using typename base_type::mem_fn_tag;
using typename base_type::obj_tag;
template <class... T>
using is_invocable_using = boost::compat::is_nothrow_invocable_r<R, T..., Args...>;
public:
template <class F, enable_if_t<std::is_function<F>::value && is_invocable_using<F>::value, int> = 0>
function_ref(F* fn) noexcept : base_type(fp_tag{}, fn) {}
template <class F, class T = remove_reference_t<F>,
enable_if_t<!std::is_same<remove_cvref_t<F>, function_ref>::value && !std::is_member_pointer<T>::value &&
is_invocable_using<T&>::value,
int> = 0>
function_ref(F&& fn) noexcept : base_type(obj_tag{}, fn) {}
#if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
template <auto f, class F = decltype(f), enable_if_t<is_invocable_using<F>::value, int> = 0>
function_ref(nontype_t<f> x) noexcept : base_type(mem_fn_tag{}, x) {}
template <auto f, class U, class T = remove_reference_t<U>, class F = decltype(f),
enable_if_t<!std::is_rvalue_reference_v<U&&> && is_invocable_using<F, T&>::value, int> = 0>
function_ref(nontype_t<f> x, U&& obj) noexcept : base_type(mem_fn_tag{}, x, std::forward<U>(obj)) {}
template <auto f, class T, class F = decltype(f), enable_if_t<is_invocable_using<F, T*>::value, int> = 0>
function_ref(nontype_t<f> x, T* obj) noexcept : base_type(mem_fn_tag{}, x, obj) {}
#endif
function_ref(const function_ref&) noexcept = default;
function_ref& operator=(const function_ref&) noexcept = default;
template <class T, enable_if_t<!std::is_same<T, function_ref>::value && !std::is_pointer<T>::value, int> = 0>
function_ref& operator=(T) = delete;
};
template <class R, class... Args>
struct function_ref<R(Args...) const noexcept> : public detail::function_ref_base<true, true, R, Args...> {
private:
using base_type = detail::function_ref_base<true, true, R, Args...>;
using typename base_type::fp_tag;
using typename base_type::mem_fn_tag;
using typename base_type::obj_tag;
template <class... T>
using is_invocable_using = boost::compat::is_nothrow_invocable_r<R, T..., Args...>;
public:
template <class F, enable_if_t<std::is_function<F>::value && is_invocable_using<F>::value, int> = 0>
function_ref(F* fn) noexcept : base_type(fp_tag{}, fn) {}
template <class F, class T = remove_reference_t<F>,
enable_if_t<!std::is_same<remove_cvref_t<F>, function_ref>::value && !std::is_member_pointer<T>::value &&
is_invocable_using<T const&>::value,
int> = 0>
function_ref(F&& fn) noexcept : base_type(obj_tag{}, fn) {}
#if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
template <auto f, class F = decltype(f), enable_if_t<is_invocable_using<F>::value, int> = 0>
function_ref(nontype_t<f> x) noexcept : base_type(mem_fn_tag{}, x) {}
template <auto f, class U, class T = remove_reference_t<U>, class F = decltype(f),
enable_if_t<!std::is_rvalue_reference_v<U&&> && is_invocable_using<F, T const&>::value, int> = 0>
function_ref(nontype_t<f> x, U&& obj) noexcept : base_type(mem_fn_tag{}, x, std::forward<U>(obj)) {}
template <auto f, class T, class F = decltype(f), enable_if_t<is_invocable_using<F, T const*>::value, int> = 0>
function_ref(nontype_t<f> x, T const* obj) noexcept : base_type(mem_fn_tag{}, x, obj) {}
#endif
function_ref(const function_ref&) noexcept = default;
function_ref& operator=(const function_ref&) noexcept = default;
template <class T, enable_if_t<!std::is_same<T, function_ref>::value && !std::is_pointer<T>::value, int> = 0>
function_ref& operator=(T) = delete;
};
#endif
} // namespace compat
} // namespace boost
#endif // #ifndef BOOST_COMPAT_FUNCTION_REF_HPP_INCLUDED

View File

@@ -2,6 +2,7 @@
#define BOOST_COMPAT_TYPE_TRAITS_HPP_INCLUDED
// Copyright 2024 Peter Dimov
// Copyright 2024 Christian Mazakas
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
@@ -32,6 +33,8 @@ template<class...> struct make_void
template<class... T> using void_t = typename detail::make_void<T...>::type;
template<class T> using add_const_t = typename std::add_const<T>::type;
} // namespace compat
} // namespace boost

View File

@@ -4,7 +4,8 @@
# https://www.boost.org/LICENSE_1_0.txt
import testing ;
import ../../config/checks/config : requires ;
import-search /boost/config/checks ;
import config : requires ;
project
: default-build
@@ -20,6 +21,15 @@ project
<toolset>msvc:<warnings-as-errors>on
<toolset>gcc:<warnings-as-errors>on
<toolset>clang:<warnings-as-errors>on
<library>/boost/core//boost_core
<library>/boost/mp11//boost_mp11
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81601
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91146
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92397
<toolset>gcc,<undefined-sanitizer>norecover:<cxxflags>"-Wno-array-bounds"
<toolset>gcc,<address-sanitizer>norecover:<cxxflags>"-Wno-array-bounds"
;
run quick.cpp ;
@@ -94,3 +104,11 @@ compile invoke_r_md_constexpr_test.cpp
run is_invocable_r_test.cpp ;
run is_nothrow_invocable_r_test.cpp ;
run function_ref_fn_test.cpp ;
run function_ref_obj_test.cpp ;
run function_ref_mfn_test.cpp ;
run function_ref_fn_noexcept_test.cpp ;
run function_ref_mfn_noexcept_test.cpp ;
run function_ref_obj_noexcept_test.cpp ;

View File

@@ -39,7 +39,7 @@ int main()
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, &x )(), -1 );
}
#if !BOOST_WORKAROUND(BOOST_MSVC, >= 1920 && BOOST_MSVC < 1940)
#if !BOOST_WORKAROUND(BOOST_MSVC, >= 1920 && BOOST_MSVC < 1950)
{
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, Y() )(), -1 );

View File

@@ -39,7 +39,7 @@ int main()
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, &x )(), -1 );
}
#if !BOOST_WORKAROUND(BOOST_MSVC, >= 1920 && BOOST_MSVC < 1940)
#if !BOOST_WORKAROUND(BOOST_MSVC, >= 1920 && BOOST_MSVC < 1950)
{
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, Y() )(), -1 );

View File

@@ -14,4 +14,4 @@ target_link_libraries(quick Boost::compat)
enable_testing()
add_test(quick quick)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)
add_custom_target(check VERBATIM COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)

View File

@@ -18,4 +18,4 @@ target_link_libraries(quick Boost::compat)
enable_testing()
add_test(quick quick)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)
add_custom_target(check VERBATIM COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)

View File

@@ -0,0 +1,165 @@
// Copyright 2024 Christian Mazakas
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/config/pragma_message.hpp>
#if !defined(__cpp_noexcept_function_type)
BOOST_PRAGMA_MESSAGE("Test skipped, __cpp_noexcept_function_type is not defined")
int main() {}
#else
#include <boost/compat/function_ref.hpp>
#include <boost/config.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
int f0() { return -1; }
int f1(int x1) noexcept { return x1; }
int g1(int x1) noexcept { return x1 * 2; }
int f2(int x1, int x2) { return 10 * x1 + x2; }
int f3(int x1, int x2, int x3) noexcept { return 100 * x1 + 10 * x2 + x3; }
int g(std::unique_ptr<int> p, std::unique_ptr<int> q) { return 10 * *p + *q; }
struct X {
int v = 0;
X() = default;
X(int v_) noexcept : v{v_} {}
};
struct Y {
int v = 0;
Y() = default;
explicit Y(int v_) : v{v_} {}
};
struct Z {
int v = 0;
Z() = default;
Z(int v_) : v{v_} {}
};
namespace compat = boost::compat;
int main() {
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<int() noexcept>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<int() const noexcept>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<int(int) noexcept>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<int(int) const noexcept>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<int(int, int) noexcept>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<int(int, int) const noexcept>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<int(int, int, int) noexcept>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<int(int, int, int) const noexcept>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<X(int, int, int) noexcept>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<X(int, int, int) const noexcept>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<void(int, int, int) noexcept>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<void(int, int, int) const noexcept>>));
struct W {
int w_;
};
BOOST_TEST_TRAIT_FALSE((std::is_assignable<compat::function_ref<int() noexcept>, W>));
BOOST_TEST_TRAIT_FALSE((std::is_assignable<compat::function_ref<int() const noexcept>, W>));
BOOST_TEST_TRAIT_FALSE((std::is_assignable<compat::function_ref<int() noexcept>, compat::function_ref<int()>>));
BOOST_TEST_TRAIT_FALSE((std::is_assignable<compat::function_ref<int()>, compat::function_ref<int() noexcept>>));
BOOST_TEST_TRAIT_FALSE(
(std::is_assignable<compat::function_ref<int() const noexcept>, compat::function_ref<int() const>>));
BOOST_TEST_TRAIT_FALSE(
(std::is_assignable<compat::function_ref<int() noexcept>, compat::function_ref<int(int) noexcept>>));
BOOST_TEST_TRAIT_FALSE(
(std::is_assignable<compat::function_ref<int(int) noexcept>, compat::function_ref<int() noexcept>>));
// f0
{
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<int() noexcept>, decltype(f0)>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<int() const noexcept>, decltype(f0)>));
}
// f1
{
compat::function_ref<int(int) noexcept> fv1(f1);
BOOST_TEST_EQ(fv1(1), 1);
compat::function_ref<int(int) const noexcept> fv2(f1);
BOOST_TEST_EQ(fv2(1), 1);
}
// f2
{
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<int(int, int) noexcept>, decltype(f2)>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<int(int, int) const noexcept>, decltype(f2)>));
}
// f3
{
compat::function_ref<int(int, int, int) noexcept> fv1(f3);
BOOST_TEST_EQ(fv1(1, 2, 3), 123);
compat::function_ref<int(int, int, int) const noexcept> fv2(f3);
BOOST_TEST_EQ(fv2(1, 2, 3), 123);
}
// g
{
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(std::unique_ptr<int>, std::unique_ptr<int>) noexcept>,
decltype(g)>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(std::unique_ptr<int>, std::unique_ptr<int>) const noexcept>,
decltype(g)>));
}
// invoke_r
{
compat::function_ref<X(int, int, int) noexcept> fv1(f3);
BOOST_TEST_EQ(fv1(1, 2, 3).v, 123);
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<Y(int, int, int) noexcept>, decltype(f3)>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<Z(int, int, int) noexcept>, decltype(f3)>));
compat::function_ref<X(int, int, int) const noexcept> fv2(f3);
BOOST_TEST_EQ(fv2(1, 2, 3).v, 123);
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<Y(int, int, int) const noexcept>, decltype(f3)>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<Z(int, int, int) const noexcept>, decltype(f3)>));
compat::function_ref<void(int, int, int) noexcept> fv3(f3);
fv3(1, 2, 3);
compat::function_ref<void(int, int, int) const noexcept> fv4(f3);
fv4(1, 2, 3);
}
// copy construct, copy assign
{
compat::function_ref<int(int) noexcept> fv(f1);
compat::function_ref<int(int) noexcept> fv2(fv);
BOOST_TEST_EQ(fv(42), fv2(42));
fv2 = g1;
BOOST_TEST_EQ(fv2(12), 24);
compat::function_ref<int(int) const noexcept> cfv(f1);
compat::function_ref<int(int) const noexcept> cfv2(cfv);
BOOST_TEST_EQ(cfv(42), cfv2(42));
cfv2 = g1;
BOOST_TEST_EQ(cfv2(24), 48);
}
return boost::report_errors();
}
#endif

View File

@@ -0,0 +1,183 @@
// Copyright 2024 Christian Mazakas
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(__GNUC__) && __GNUC__ == 7
#pragma GCC diagnostic ignored "-Wnoexcept-type"
#endif
#include <boost/compat/function_ref.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#include <boost/config/workaround.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
int f0() { return -1; }
int g0() { return 7331; }
int f1(int x1) noexcept { return x1; }
int f2(int x1, int x2) { return 10 * x1 + x2; }
int f3(int x1, int x2, int x3) noexcept { return 100 * x1 + 10 * x2 + x3; }
int g(std::unique_ptr<int> p, std::unique_ptr<int> q) { return 10 * *p + *q; }
struct X {
int v = 0;
X() = default;
X(int v_) noexcept : v{v_} {}
};
struct Y {
int v = 0;
Y() = default;
explicit Y(int v_) : v{v_} {}
};
struct Z {
int v = 0;
Z() = default;
Z(int v_) : v{v_} {}
};
namespace compat = boost::compat;
int main() {
#if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS)
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<int()>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<int() const>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<int(int)>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<int(int) const>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<int(int, int)>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<int(int, int) const>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<int(int, int, int)>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<int(int, int, int) const>>));
BOOST_TEST_TRAIT_TRUE(
(std::is_trivially_copyable<compat::function_ref<int(std::unique_ptr<int>, std::unique_ptr<int>)>>));
BOOST_TEST_TRAIT_TRUE(
(std::is_trivially_copyable<compat::function_ref<int(std::unique_ptr<int>, std::unique_ptr<int>) const>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<X(int, int, int)>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<X(int, int, int) const>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<void(int, int, int)>>));
BOOST_TEST_TRAIT_TRUE((std::is_trivially_copyable<compat::function_ref<void(int, int, int) const>>));
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
struct W {
int w_;
};
BOOST_TEST_TRAIT_FALSE((std::is_assignable<compat::function_ref<int()>, W>));
BOOST_TEST_TRAIT_FALSE((std::is_assignable<compat::function_ref<int() const>, W>));
BOOST_TEST_TRAIT_FALSE((std::is_assignable<compat::function_ref<int()>, compat::function_ref<int() const>>));
BOOST_TEST_TRAIT_FALSE((std::is_assignable<compat::function_ref<int() const>, compat::function_ref<int()>>));
BOOST_TEST_TRAIT_FALSE((std::is_assignable<compat::function_ref<int()>, compat::function_ref<int(int)>>));
BOOST_TEST_TRAIT_FALSE((std::is_assignable<compat::function_ref<int(int)>, compat::function_ref<int()>>));
#endif
#else
BOOST_PRAGMA_MESSAGE("<type_traits> is incomplete, skipping is_trivially_copyable checks")
#endif
// f0
{
compat::function_ref<int()> fv1(f0);
BOOST_TEST_EQ(fv1(), -1);
compat::function_ref<int() const> fv2(f0);
BOOST_TEST_EQ(fv2(), -1);
}
// f1
{
compat::function_ref<int(int)> fv1(f1);
BOOST_TEST_EQ(fv1(1), 1);
compat::function_ref<int(int) const> fv2(f1);
BOOST_TEST_EQ(fv2(1), 1);
}
// f2
{
compat::function_ref<int(int, int)> fv1(f2);
BOOST_TEST_EQ(fv1(1, 2), 12);
compat::function_ref<int(int, int) const> fv2(f2);
BOOST_TEST_EQ(fv2(1, 2), 12);
}
// f3
{
compat::function_ref<int(int, int, int)> fv1(f3);
BOOST_TEST_EQ(fv1(1, 2, 3), 123);
compat::function_ref<int(int, int, int) const> fv2(f3);
BOOST_TEST_EQ(fv2(1, 2, 3), 123);
}
// g
{
using S1 = int(std::unique_ptr<int>, std::unique_ptr<int>);
using S2 = int(std::unique_ptr<int>, std::unique_ptr<int>) const;
compat::function_ref<S1> fv1(g);
{
auto p = std::unique_ptr<int>(new int{1});
auto q = std::unique_ptr<int>(new int{2});
BOOST_TEST_EQ(fv1(std::move(p), std::move(q)), 12);
}
compat::function_ref<S2> fv2(g);
{
auto p = std::unique_ptr<int>(new int{130});
auto q = std::unique_ptr<int>(new int{37});
BOOST_TEST_EQ(fv1(std::move(p), std::move(q)), 1337);
}
}
// invoke_r
{
compat::function_ref<X(int, int, int)> fv1(f3);
BOOST_TEST_EQ(fv1(1, 2, 3).v, 123);
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<Y(int, int, int)>, decltype(f3)>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<Z(int, int, int)>, decltype(f3)>));
compat::function_ref<X(int, int, int) const> fv2(f3);
BOOST_TEST_EQ(fv2(1, 2, 3).v, 123);
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<Y(int, int, int) const>, decltype(f3)>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<Z(int, int, int) const>, decltype(f3)>));
compat::function_ref<void(int, int, int)> fv3(f3);
fv3(1, 2, 3);
compat::function_ref<void(int, int, int) const> fv4(f3);
fv4(1, 2, 3);
}
// copy construct, copy assign
{
compat::function_ref<int()> fv(f0);
compat::function_ref<int()> fv2(fv);
BOOST_TEST_EQ(fv(), fv2());
fv2 = g0;
BOOST_TEST_EQ(fv2(), 7331);
compat::function_ref<int() const> cfv(f0);
compat::function_ref<int() const> cfv2(cfv);
BOOST_TEST_EQ(cfv(), cfv2());
cfv2 = g0;
BOOST_TEST_EQ(cfv2(), 7331);
}
return boost::report_errors();
}

View File

@@ -0,0 +1,164 @@
// Copyright 2024 Christian Mazakas
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(__GNUC__) && __GNUC__ == 7
#pragma GCC diagnostic ignored "-Wnoexcept-type"
#endif
#include <boost/compat/function_ref.hpp>
#if !defined(BOOST_COMPAT_HAS_AUTO_NTTP)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("no support for placeholder NTTPs detected, skipping this test")
int main() {}
#else
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <memory>
#include <type_traits>
struct F1 {
std::unique_ptr<int> p_;
F1() : p_(new int(1)) {}
int m1() { return *p_ + -1; }
int m2(int x1) noexcept { return 10 * *p_ + x1; }
int m3(int x1, int x2) const { return 100 * *p_ + 10 * x1 + x2; }
int m4(int x1, int x2, int x3) const noexcept { return 1000 * *p_ + 100 * x1 + 10 * x2 + x3; }
};
namespace compat = boost::compat;
int main() {
{
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(F1&) noexcept>, compat::nontype_t<&F1::m1>>));
BOOST_TEST_TRAIT_TRUE(
(std::is_constructible<compat::function_ref<int(F1&, int) noexcept>, compat::nontype_t<&F1::m2>>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(F1&, int, int) noexcept>, compat::nontype_t<&F1::m3>>));
BOOST_TEST_TRAIT_TRUE(
(std::is_constructible<compat::function_ref<int(F1&, int, int, int) noexcept>, compat::nontype_t<&F1::m4>>));
}
{
F1 f1;
compat::function_ref<int(F1&, int) noexcept> fn2(compat::nontype_t<&F1::m2>{});
BOOST_TEST_EQ(fn2(f1, 2), 12);
compat::function_ref<int(F1&, int, int, int) noexcept> fn4(compat::nontype_t<&F1::m4>{});
BOOST_TEST_EQ(fn4(f1, 2, 3, 4), 1234);
}
{
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(F1&) const noexcept>, compat::nontype_t<&F1::m1>>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(F1&, int, int) const noexcept>, compat::nontype_t<&F1::m3>>));
F1 f1;
compat::function_ref<int(F1&, int) const noexcept> fn2(compat::nontype_t<&F1::m2>{});
BOOST_TEST_EQ(fn2(f1, 2), 12);
compat::function_ref<int(F1&, int, int, int) const noexcept> fn4(compat::nontype_t<&F1::m4>{});
BOOST_TEST_EQ(fn4(f1, 2, 3, 4), 1234);
}
{
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(F1 const&) noexcept>, compat::nontype_t<&F1::m1>>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(F1 const&, int) noexcept>, compat::nontype_t<&F1::m2>>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(F1 const&, int, int) noexcept>, compat::nontype_t<&F1::m3>>));
F1 f1;
compat::function_ref<int(F1 const&, int, int, int) noexcept> fn4(compat::nontype_t<&F1::m4>{});
BOOST_TEST_EQ(fn4(f1, 2, 3, 4), 1234);
}
{
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int() noexcept>, compat::nontype_t<&F1::m1>, F1&>));
BOOST_TEST_TRAIT_TRUE(
(std::is_constructible<compat::function_ref<int(int) noexcept>, compat::nontype_t<&F1::m2>, F1&>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(int, int) noexcept>, compat::nontype_t<&F1::m3>, F1&>));
BOOST_TEST_TRAIT_TRUE(
(std::is_constructible<compat::function_ref<int(int, int, int) noexcept>, compat::nontype_t<&F1::m4>, F1&>));
F1 f1;
compat::function_ref<int(int) noexcept> fn2(compat::nontype_t<&F1::m2>{}, f1);
BOOST_TEST_EQ(fn2(2), 12);
compat::function_ref<int(int, int, int) noexcept> fn4(compat::nontype_t<&F1::m4>{}, f1);
BOOST_TEST_EQ(fn4(2, 3, 4), 1234);
}
{
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int() const noexcept>, compat::nontype_t<&F1::m1>, F1 const&>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(int) const noexcept>, compat::nontype_t<&F1::m2>, F1 const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<int(int, int) const noexcept>,
compat::nontype_t<&F1::m3>, F1 const&>));
F1 f1;
compat::function_ref<int(int, int, int) const noexcept> fn4(compat::nontype_t<&F1::m4>{}, f1);
BOOST_TEST_EQ(fn4(2, 3, 4), 1234);
auto const& f1_2 = f1;
compat::function_ref<int(int, int, int) const noexcept> fn4_2(compat::nontype_t<&F1::m4>{}, f1_2);
BOOST_TEST_EQ(fn4_2(2, 3, 4), 1234);
}
{
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int() noexcept>, compat::nontype_t<&F1::m1>, F1*>));
BOOST_TEST_TRAIT_TRUE(
(std::is_constructible<compat::function_ref<int(int) noexcept>, compat::nontype_t<&F1::m2>, F1*>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(int, int) noexcept>, compat::nontype_t<&F1::m3>, F1*>));
BOOST_TEST_TRAIT_TRUE(
(std::is_constructible<compat::function_ref<int(int, int, int) noexcept>, compat::nontype_t<&F1::m4>, F1*>));
F1 f1;
compat::function_ref<int(int) noexcept> fn2(compat::nontype_t<&F1::m2>{}, &f1);
BOOST_TEST_EQ(fn2(2), 12);
compat::function_ref<int(int, int, int) noexcept> fn4(compat::nontype_t<&F1::m4>{}, &f1);
BOOST_TEST_EQ(fn4(2, 3, 4), 1234);
}
{
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int() const noexcept>, compat::nontype_t<&F1::m1>, F1 const*>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(int) const noexcept>, compat::nontype_t<&F1::m2>, F1 const*>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<int(int, int) const noexcept>,
compat::nontype_t<&F1::m3>, F1 const*>));
F1 const f1;
compat::function_ref<int(int, int, int) const noexcept> fn4(compat::nontype_t<&F1::m4>{}, &f1);
BOOST_TEST_EQ(fn4(2, 3, 4), 1234);
auto const& f1_2 = f1;
compat::function_ref<int(int, int, int) const noexcept> fn4_2(compat::nontype_t<&F1::m4>{}, &f1_2);
BOOST_TEST_EQ(fn4_2(2, 3, 4), 1234);
}
return boost::report_errors();
}
#endif

View File

@@ -0,0 +1,176 @@
// Copyright 2024 Christian Mazakas
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(__GNUC__) && __GNUC__ == 7
#pragma GCC diagnostic ignored "-Wnoexcept-type"
#endif
#include <boost/compat/function_ref.hpp>
#if !defined(BOOST_COMPAT_HAS_AUTO_NTTP)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("no support for placeholder NTTPs detected, skipping this test")
int main() {}
#else
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <memory>
#include <type_traits>
struct F1 {
std::unique_ptr<int> p_;
int q_ = 1337;
F1() : p_(new int(1)) {}
int m1() { return *p_ + -1; }
int m2(int x1) noexcept { return 10 * *p_ + x1; }
int m3(int x1, int x2) const { return 100 * *p_ + 10 * x1 + x2; }
int m4(int x1, int x2, int x3) const noexcept { return 1000 * *p_ + 100 * x1 + 10 * x2 + x3; }
};
namespace compat = boost::compat;
int main() {
{
F1 f1;
compat::function_ref<int(F1&)> fn1(compat::nontype_t<&F1::m1>{});
BOOST_TEST_EQ(fn1(f1), 0);
compat::function_ref<int(F1&, int)> fn2(compat::nontype_t<&F1::m2>{});
BOOST_TEST_EQ(fn2(f1, 2), 12);
compat::function_ref<int(F1&, int, int)> fn3(compat::nontype_t<&F1::m3>{});
BOOST_TEST_EQ(fn3(f1, 2, 3), 123);
compat::function_ref<int(F1&, int, int, int)> fn4(compat::nontype_t<&F1::m4>{});
BOOST_TEST_EQ(fn4(f1, 2, 3, 4), 1234);
compat::function_ref<int(F1&)> a1(compat::nontype_t<&F1::q_>{});
BOOST_TEST_EQ(a1(f1), 1337);
}
{
F1 f1;
compat::function_ref<int(F1&) const> fn1(compat::nontype_t<&F1::m1>{});
BOOST_TEST_EQ(fn1(f1), 0);
compat::function_ref<int(F1&, int) const> fn2(compat::nontype_t<&F1::m2>{});
BOOST_TEST_EQ(fn2(f1, 2), 12);
compat::function_ref<int(F1&, int, int) const> fn3(compat::nontype_t<&F1::m3>{});
BOOST_TEST_EQ(fn3(f1, 2, 3), 123);
compat::function_ref<int(F1&, int, int, int) const> fn4(compat::nontype_t<&F1::m4>{});
BOOST_TEST_EQ(fn4(f1, 2, 3, 4), 1234);
}
{
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<int(F1 const&)>, compat::nontype_t<&F1::m1>>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(F1 const&, int)>, compat::nontype_t<&F1::m2>>));
F1 f1;
compat::function_ref<int(F1 const&, int, int) const> fn3(compat::nontype_t<&F1::m3>{});
BOOST_TEST_EQ(fn3(f1, 2, 3), 123);
compat::function_ref<int(F1 const&, int, int, int) const> fn4(compat::nontype_t<&F1::m4>{});
BOOST_TEST_EQ(fn4(f1, 2, 3, 4), 1234);
auto const& f2 = f1;
compat::function_ref<int(F1 const&, int, int) const> fn23(compat::nontype_t<&F1::m3>{});
BOOST_TEST_EQ(fn3(f2, 2, 3), 123);
compat::function_ref<int(F1 const&, int, int, int) const> fn24(compat::nontype_t<&F1::m4>{});
BOOST_TEST_EQ(fn4(f2, 2, 3, 4), 1234);
}
{
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<int(int)>, compat::nontype_t<&F1::m2>, F1&>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(int)>, compat::nontype_t<&F1::m2>, F1 const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<int(int)>, compat::nontype_t<&F1::m2>, F1&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<int(int)>, compat::nontype_t<&F1::m2>, F1>));
BOOST_TEST_TRAIT_TRUE(
(std::is_constructible<compat::function_ref<int(int, int) const>, compat::nontype_t<&F1::m3>, F1&>));
BOOST_TEST_TRAIT_TRUE(
(std::is_constructible<compat::function_ref<int(int, int) const>, compat::nontype_t<&F1::m3>, F1 const&>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(int, int) const>, compat::nontype_t<&F1::m3>, F1&&>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(int, int) const>, compat::nontype_t<&F1::m3>, F1>));
}
{
F1 f1;
compat::function_ref<int()> fn1(compat::nontype_t<&F1::m1>{}, f1);
BOOST_TEST_EQ(fn1(), 0);
compat::function_ref<int(int)> fn2(compat::nontype_t<&F1::m2>{}, f1);
BOOST_TEST_EQ(fn2(2), 12);
compat::function_ref<int(int, int)> fn3(compat::nontype_t<&F1::m3>{}, f1);
BOOST_TEST_EQ(fn3(2, 3), 123);
compat::function_ref<int(int, int, int)> fn4(compat::nontype_t<&F1::m4>{}, f1);
BOOST_TEST_EQ(fn4(2, 3, 4), 1234);
}
{
F1 const f1;
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<int() const>, compat::nontype_t<&F1::m1>, F1&>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(int) const>, compat::nontype_t<&F1::m2>, F1&>));
compat::function_ref<int(int, int) const> fn3(compat::nontype_t<&F1::m3>{}, f1);
BOOST_TEST_EQ(fn3(2, 3), 123);
compat::function_ref<int(int, int, int) const> fn4(compat::nontype_t<&F1::m4>{}, f1);
BOOST_TEST_EQ(fn4(2, 3, 4), 1234);
}
{
F1 f1;
compat::function_ref<int()> fn1(compat::nontype_t<&F1::m1>{}, &f1);
BOOST_TEST_EQ(fn1(), 0);
compat::function_ref<int(int)> fn2(compat::nontype_t<&F1::m2>{}, &f1);
BOOST_TEST_EQ(fn2(2), 12);
compat::function_ref<int(int, int)> fn3(compat::nontype_t<&F1::m3>{}, &f1);
BOOST_TEST_EQ(fn3(2, 3), 123);
compat::function_ref<int(int, int, int)> fn4(compat::nontype_t<&F1::m4>{}, &f1);
BOOST_TEST_EQ(fn4(2, 3, 4), 1234);
}
{
F1 const f1;
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int() const>, compat::nontype_t<&F1::m1>, F1 const*>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(int) const>, compat::nontype_t<&F1::m2>, F1 const*>));
compat::function_ref<int(int, int) const> fn3(compat::nontype_t<&F1::m3>{}, &f1);
BOOST_TEST_EQ(fn3(2, 3), 123);
compat::function_ref<int(int, int, int) const> fn4(compat::nontype_t<&F1::m4>{}, &f1);
BOOST_TEST_EQ(fn4(2, 3, 4), 1234);
}
return boost::report_errors();
}
#endif

View File

@@ -0,0 +1,228 @@
// Copyright 2024 Christian Mazakas
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/config/pragma_message.hpp>
#if !defined(__cpp_noexcept_function_type)
BOOST_PRAGMA_MESSAGE("Test skipped, __cpp_noexcept_function_type is not defined")
int main() {}
#else
#include <boost/compat/function_ref.hpp>
#include <boost/config.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
struct F1 {
int operator()() { return -1; }
int operator()(int x1) noexcept { return x1; }
int operator()(int x1, int x2) const { return 10 * x1 + x2; }
int operator()(int x1, int x2, int x3) const noexcept { return 100 * x1 + 10 * x2 + x3; }
};
struct F2 {
int operator()(int x1, int x2) & { return 100 * x1 + 10 * x2 + 1; }
int operator()(int x1, int x2) const& { return 100 * x1 + 10 * x2 + 2; }
int operator()(int x1, int x2) && { return 100 * x1 + 10 * x2 + 3; }
int operator()(int x1, int x2) const&& { return 100 * x1 + 10 * x2 + 4; }
};
struct X {
int v = 0;
X() = default;
X(int v_) noexcept : v{v_} {}
};
struct Y {
int v = 0;
Y() = default;
explicit Y(int v_) : v{v_} {}
};
struct Z {
int v = 0;
Z() = default;
Z(int v_) : v{v_} {}
};
namespace compat = boost::compat;
int main() {
{
F1 f1;
{
using S1 = int() noexcept;
using S2 = int(int) noexcept;
using S3 = int(int, int) noexcept;
using S4 = int(int, int, int) noexcept;
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1 const>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1 const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1 const&&>));
compat::function_ref<S2> fv2(f1);
BOOST_TEST_EQ(fv2(1), 1);
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F1 const>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F1 const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F1 const&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S3>, F1>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S3>, F1&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S3>, F1&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S3>, F1 const>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S3>, F1 const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S3>, F1 const&&>));
compat::function_ref<S4> fv4(f1);
BOOST_TEST_EQ(fv4(1, 2, 3), 123);
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1&>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1&&>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1 const>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1 const&>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1 const&&>));
}
{
using S1 = int() const noexcept;
using S2 = int(int) const noexcept;
using S3 = int(int, int) const noexcept;
using S4 = int(int, int, int) const noexcept;
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1 const>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1 const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1 const&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F1>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F1&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F1&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F1 const>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F1 const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F1 const&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S3>, F1>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S3>, F1&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S3>, F1&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S3>, F1 const>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S3>, F1 const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S3>, F1 const&&>));
compat::function_ref<S4> fv4(f1);
BOOST_TEST_EQ(fv4(1, 2, 3), 123);
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1&>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1&&>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1 const>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1 const&>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1 const&&>));
}
{
using S2 = int(int) noexcept;
using S4 = int(int, int, int) noexcept;
auto& fref = f1;
compat::function_ref<S2> fv2(fref);
BOOST_TEST_EQ(fv2(1), 1);
auto const& cfref = f1;
compat::function_ref<S4> fv4(cfref);
BOOST_TEST_EQ(fv4(1, 2, 3), 123);
}
{
using S4 = int(int, int, int) const noexcept;
auto const& cfref = f1;
compat::function_ref<S4> fv4(cfref);
BOOST_TEST_EQ(fv4(1, 2, 3), 123);
}
}
{
using S1 = int(int, int) noexcept;
using S2 = int(int, int) const noexcept;
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F2>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F2&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F2&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F2 const>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F2 const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F2 const&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F2>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F2&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F2&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F2 const>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F2 const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F2 const&&>));
}
// invoke_r
{
F1 f;
compat::function_ref<X(int, int, int) noexcept> fv1(f);
BOOST_TEST_EQ(fv1(1, 2, 3).v, 123);
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<Y(int, int, int) noexcept>, F1>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<Z(int, int, int) noexcept>, F1>));
compat::function_ref<X(int, int, int) const noexcept> fv2(f);
BOOST_TEST_EQ(fv2(1, 2, 3).v, 123);
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<Y(int, int, int) const noexcept>, F1>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<Z(int, int, int) const noexcept>, F1>));
compat::function_ref<void(int, int, int) noexcept> fv3(f);
fv3(1, 2, 3);
compat::function_ref<void(int, int, int) const noexcept> fv4(f);
fv4(1, 2, 3);
}
// copy construct, copy assign
{
F1 f;
auto id = [](int x) noexcept { return x + 7331; };
compat::function_ref<int(int) noexcept> fv(f);
compat::function_ref<int(int) noexcept> fv2(fv);
BOOST_TEST_EQ(fv(12), fv2(12));
fv2 = compat::function_ref<int(int) noexcept>(id);
BOOST_TEST_EQ(fv2(1), 7332);
auto add = [](int x, int y, int z) noexcept { return x + y + z; };
compat::function_ref<int(int, int, int) const noexcept> cfv(f);
compat::function_ref<int(int, int, int) const noexcept> cfv2(cfv);
BOOST_TEST_EQ(cfv(1, 2, 3), cfv2(1, 2, 3));
cfv2 = compat::function_ref<int(int, int, int) const noexcept>(add);
BOOST_TEST_EQ(cfv2(1, 2, 3), 6);
}
return boost::report_errors();
}
#endif

View File

@@ -0,0 +1,260 @@
// Copyright 2024 Christian Mazakas
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/function_ref.hpp>
#include <boost/config.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
struct F1 {
int operator()() { return -1; }
int operator()(int x1) noexcept { return x1; }
int operator()(int x1, int x2) const { return 10 * x1 + x2; }
int operator()(int x1, int x2, int x3) const noexcept { return 100 * x1 + 10 * x2 + x3; }
};
struct F2 {
int operator()(int x1, int x2) & { return 100 * x1 + 10 * x2 + 1; }
int operator()(int x1, int x2) const& { return 100 * x1 + 10 * x2 + 2; }
int operator()(int x1, int x2) && { return 100 * x1 + 10 * x2 + 3; }
int operator()(int x1, int x2) const&& { return 100 * x1 + 10 * x2 + 4; }
};
struct X {
int v = 0;
X() = default;
X(int v_) noexcept : v{v_} {}
};
struct Y {
int v = 0;
Y() = default;
explicit Y(int v_) : v{v_} {}
};
struct Z {
int v = 0;
Z() = default;
Z(int v_) : v{v_} {}
};
namespace compat = boost::compat;
int main() {
{
F1 f;
{
using S1 = int();
using S2 = int(int);
using S3 = int(int, int);
using S4 = int(int, int, int);
compat::function_ref<S1> fv1(f);
BOOST_TEST_EQ(fv1(), -1);
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1 const>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1 const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1 const&&>));
compat::function_ref<S2> fv2(f);
BOOST_TEST_EQ(fv2(1), 1);
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F1 const>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F1 const&>));
compat::function_ref<S3> fv3(f);
BOOST_TEST_EQ(fv3(1, 2), 12);
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S3>, F1>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S3>, F1&>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S3>, F1&&>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S3>, F1 const>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S3>, F1 const&>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S3>, F1 const&&>));
compat::function_ref<S4> fv4(f);
BOOST_TEST_EQ(fv4(1, 2, 3), 123);
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1&>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1&&>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1 const>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1 const&>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1 const&&>));
}
{
using S1 = int() const;
using S2 = int(int) const;
using S3 = int(int, int) const;
using S4 = int(int, int, int) const;
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1 const>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1 const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1 const&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F1>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F1&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F1&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F1 const>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F1 const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S2>, F1 const&&>));
compat::function_ref<S3> fv3(f);
BOOST_TEST_EQ(fv3(1, 2), 12);
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S3>, F1>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S3>, F1&>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S3>, F1&&>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S3>, F1 const>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S3>, F1 const&>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S3>, F1 const&&>));
compat::function_ref<S4> fv4(f);
BOOST_TEST_EQ(fv4(1, 2, 3), 123);
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1&>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1&&>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1 const>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1 const&>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<S4>, F1 const&&>));
}
{
using S1 = int();
using S2 = int(int);
auto& fref = f;
compat::function_ref<S1> fv1(fref);
BOOST_TEST_EQ(fv1(), -1);
compat::function_ref<S2> fv2(fref);
BOOST_TEST_EQ(fv2(1), 1);
}
{
using S1 = int();
using S2 = int(int);
compat::function_ref<S1> fv1(std::move(f));
BOOST_TEST_EQ(fv1(), -1);
compat::function_ref<S2> fv2(std::move(f));
BOOST_TEST_EQ(fv2(1), 1);
}
{
using S3 = int(int, int) const;
using S4 = int(int, int, int) const;
auto const& fref = f;
compat::function_ref<S3> fv3(fref);
BOOST_TEST_EQ(fv3(1, 2), 12);
compat::function_ref<S4> fv4(fref);
BOOST_TEST_EQ(fv4(1, 2, 3), 123);
}
{
using S3 = int(int, int) const;
using S4 = int(int, int, int) const;
auto const&& fref = std::move(f);
compat::function_ref<S3> fv3(fref);
BOOST_TEST_EQ(fv3(1, 2), 12);
compat::function_ref<S4> fv4(fref);
BOOST_TEST_EQ(fv4(1, 2, 3), 123);
}
}
{
F2 g;
{
compat::function_ref<int(int, int)> fv1(g);
BOOST_TEST_EQ(fv1(3, 2), 321);
auto& gref = g;
compat::function_ref<int(int, int)> rfv1(gref);
BOOST_TEST_EQ(rfv1(3, 2), 321);
compat::function_ref<int(int, int)> fv2(std::move(g));
BOOST_TEST_EQ(fv2(3, 2), 321);
compat::function_ref<int(int, int) const> fv3(g);
BOOST_TEST_EQ(fv3(3, 2), 322);
auto const& gcref = g;
compat::function_ref<int(int, int) const> crfv3(gcref);
BOOST_TEST_EQ(fv3(3, 2), 322);
compat::function_ref<int(int, int) const> fv4(std::move(g));
BOOST_TEST_EQ(fv4(3, 2), 322);
}
}
// invoke_r
{
F1 f;
compat::function_ref<X(int, int, int)> fv1(f);
BOOST_TEST_EQ(fv1(1, 2, 3).v, 123);
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<Y(int, int, int)>, F1>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<Z(int, int, int)>, F1>));
compat::function_ref<X(int, int, int) const> fv2(f);
BOOST_TEST_EQ(fv2(1, 2, 3).v, 123);
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<Y(int, int, int) const>, F1>));
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<Z(int, int, int) const>, F1>));
compat::function_ref<void(int, int, int)> fv3(f);
fv3(1, 2, 3);
compat::function_ref<void(int, int, int) const> fv4(f);
fv4(1, 2, 3);
}
// copy construct, copy assign
{
F1 f;
auto id = [] { return 7331; };
compat::function_ref<int()> fv(f);
compat::function_ref<int()> fv2(fv);
BOOST_TEST_EQ(fv(), fv2());
fv2 = compat::function_ref<int()>(id);
BOOST_TEST_EQ(fv2(), 7331);
auto add = [](int x, int y) { return x + y; };
compat::function_ref<int(int, int) const> cfv(f);
compat::function_ref<int(int, int) const> cfv2(cfv);
BOOST_TEST_EQ(cfv(1, 2), cfv2(1, 2));
cfv2 = compat::function_ref<int(int, int) const>(add);
BOOST_TEST_EQ(cfv2(1, 2), 3);
}
return boost::report_errors();
}

View File

@@ -29,7 +29,7 @@ int main()
BOOST_TEST_EQ( boost::compat::invoke( &X::m, &x ), -1 );
}
#if !BOOST_WORKAROUND(BOOST_MSVC, >= 1920 && BOOST_MSVC < 1940)
#if !BOOST_WORKAROUND(BOOST_MSVC, >= 1920 && BOOST_MSVC < 1950)
{
BOOST_TEST_EQ( boost::compat::invoke( &X::m, Y() ), -1 );

View File

@@ -36,7 +36,7 @@ int main()
#endif
}
#if !BOOST_WORKAROUND(BOOST_MSVC, >= 1920 && BOOST_MSVC < 1940)
#if !BOOST_WORKAROUND(BOOST_MSVC, >= 1920 && BOOST_MSVC < 1950)
{
constexpr Y y = {};