2
0
mirror of https://github.com/boostorg/compat.git synced 2026-01-19 16:12:15 +00:00

130 Commits

Author SHA1 Message Date
Peter Dimov
7ce75ac955 Update ci.yml 2026-01-16 02:16:52 +02:00
Peter Dimov
0776d62a95 Update documentation 2025-11-18 14:33:45 +02:00
Peter Dimov
904b80b8a1 Move nontype.hpp to detail 2025-11-18 14:33:45 +02:00
Peter Dimov
ffaadc079d Update .drone.jsonnet 2025-11-18 12:06:25 +02:00
Peter Dimov
ab09450342 Update documentation of function_ref 2025-11-03 18:54:47 +02:00
Peter Dimov
79ca9646ea Update documentation of nontype to clarify that it requires C++17 2025-11-03 18:41:18 +02:00
Peter Dimov
6b9e52c284 Rename detail::nontype11 to nttp_holder 2025-11-01 19:45:39 +02:00
Peter Dimov
4c9e9079c1 Remove feature check for variable templates; if we have auto template parameters (C++17) we probably have C++14 as well 2025-11-01 19:32:34 +02:00
Peter Dimov
e522245e9c Remove uses of is_rvalue_reference_v 2025-11-01 19:21:51 +02:00
Peter Dimov
cef4d529d0 Remove BOOST_COMPAT_HAS_AUTO_NTTP 2025-11-01 19:16:17 +02:00
Peter Dimov
1e3cb9cc7a Disable tests that require noexcept function types to pass 2025-11-01 19:15:14 +02:00
Peter Dimov
1226bab251 Remove use of BOOST_COMPAT_HAS_AUTO_NTTP in function_ref_mfn_noexcept_test.cpp 2025-11-01 19:00:44 +02:00
Peter Dimov
f9dd6181fb Remove use of BOOST_COMPAT_HAS_AUTO_NTTP in function_ref_mfn_test.cpp 2025-11-01 18:51:37 +02:00
Peter Dimov
db39b5075c Add a C++11 compatible base class to nontype_t; unconditionally enable the function_ref constructors for it 2025-11-01 18:36:05 +02:00
Peter Dimov
f72aeb4e59 Update documentation 2025-11-01 17:57:22 +02:00
Peter Dimov
8e7e16e9c3 Add nontype_test.cpp 2025-11-01 17:18:55 +02:00
Peter Dimov
f897f32064 Extract nontype_t to its own header; add nontype 2025-11-01 17:07:54 +02:00
Peter Dimov
a5a56ee5c0 Merge pull request #22 from k3DW/to_underlying
Add `to_underlying`
2025-09-05 18:48:05 +03:00
Braden Ganetsky
72ff680a72 Fix function signature in to_array docs 2025-09-05 09:33:40 -05:00
Braden Ganetsky
94b1675762 Add to_underlying 2025-09-05 09:33:40 -05:00
Peter Dimov
694b78df7a Update ci.yml 2025-09-04 16:08:07 +03:00
Peter Dimov
e374640265 Remove windows-2019 from ci.yml 2025-07-02 19:06:07 +03:00
Christian Mazakas
f496e814b5 update changelog 2025-07-02 07:12:23 -07:00
Peter Dimov
10e1dad9ba Merge pull request #21 from cmazakas/feature/move-only-function
add move_only_function
2025-06-28 17:52:06 +03:00
Christian Mazakas
6172b5e50f add move_only_function docs 2025-06-11 19:57:40 -07:00
Christian Mazakas
1a60e0357c add move_only_function 2025-06-11 19:57:30 -07:00
Christian Mazakas
6901952904 remove ubuntu 20 from posix cmake gha jobs 2025-05-29 15:26:16 -07:00
Christian Mazakas
a1eb40bd0e update gha to use containers 2025-05-29 15:26:16 -07:00
Christian Mazakas
61b464c3ee Merge pull request #17 from cmazakas/fix/lvalue-params
fix lvalue parameter passing
2024-12-17 12:49:24 -08:00
Christian Mazakas
c3bd40856d remove erroneous rvalue qualification 2024-12-17 11:20:57 -08:00
Christian Mazakas
736b381d13 add failing test case
Passing an lvalue ref parameter when arguments are by-value causes a failure of reference binding.
2024-12-17 11:20:18 -08:00
Peter Dimov
881cc909fb Update .drone.jsonnet 2024-12-13 03:55:39 +02:00
Peter Dimov
c9f3354cff Apply Node20 workaround 2024-12-13 03:34:16 +02:00
Peter Dimov
c4924db9e5 Update ci.yml 2024-12-13 03:21:42 +02:00
Peter Dimov
1a8bb0b574 Update revision history 2024-10-04 13:43:06 +03:00
Peter Dimov
c18e5f2276 Move MSVC workarounds from test/Jamfile to to_array_rvalue_test.cpp 2024-10-04 13:26:50 +03:00
Anarthal (Rubén Pérez)
d2d5cbe094 Added to_array (#14)
* Added to_array

* Suppress unused warnings

* Fix unused warnings (2)

* Workaround msvc 14.0 bug

* Workaround MSVC problems with moving arrays

* MSVC workaround in constexpr test

* Further MSVC fixes

* Disable rvalue tests for MSVC 14.0

* Incorrect argument spec

* constexpr checks

* const test

* Disable rvalues for msvc 14.1

* Docs

* Added more const tests

* Correct static_asserts

* Update type requirements in docs

* Corrected return types and conditions

* Doc updates
2024-10-04 13:06:44 +03:00
Peter Dimov
c49f822b2e Update .drone.jsonnet 2024-08-21 10:49:04 +03:00
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
Peter Dimov
2bc168926b Add is_nothrow_invocable_r 2024-04-06 22:20:25 +03:00
Peter Dimov
3025c1b929 Add is_invocable_r 2024-04-06 21:45:34 +03:00
Peter Dimov
04e6d2ce20 Remove unnecessary includes 2024-04-06 21:45:34 +03:00
Peter Dimov
8cfda56a62 Add constexpr tests for invoke_r 2024-04-06 21:45:19 +03:00
Peter Dimov
430c9b1b60 Add noexcept tests for invoke_r 2024-04-06 20:12:13 +03:00
Peter Dimov
a91461a442 Fix C++11 constexpr errors in invoke_r<void> 2024-04-06 19:45:44 +03:00
Peter Dimov
984d6b39da Add invoke_r 2024-04-06 19:03:58 +03:00
Peter Dimov
87e758f538 Update meta/libraries.json 2024-03-31 22:38:49 +03:00
Peter Dimov
ab2670f0a8 Merge pull request #9 from ashtum/resolve-mem_fn_ambiguity
Qualify call to `mem_fn`
2024-03-31 17:23:43 +03:00
Mohammad Nejati
0561949e15 Qualify call to mem_fn 2024-03-31 10:05:25 +00:00
Peter Dimov
5e88ebb1d1 Fix changelog 2024-03-30 22:24:04 +02:00
Peter Dimov
d071dfc91f Update documentation 2024-03-30 21:54:03 +02: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
Peter Dimov
30242af2c2 Add constexpr tests for bind_back 2024-03-29 21:43:34 +02:00
Peter Dimov
9a58caf918 Add bind_back 2024-03-29 21:20:49 +02:00
Peter Dimov
28e71552eb Add integer_sequence_test 2024-03-28 21:37:43 +02:00
Peter Dimov
10ad6ab592 Add boost/compat/integer_sequence.hpp 2024-03-28 21:28:20 +02:00
Peter Dimov
39ddb40a47 Update test/quick.cpp 2024-03-28 21:13:31 +02:00
Peter Dimov
928f2d7255 Add bind_front_md_constexpr_test 2024-03-28 21:12:46 +02:00
Peter Dimov
5a5db4a74f Add bind_front_mfn_constexpr_test 2024-03-28 21:12:46 +02:00
Peter Dimov
acd8c12e91 Add bind_front_obj_constexpr_test 2024-03-28 21:12:46 +02:00
Peter Dimov
710ea6a904 Add bind_front_fn_constexpr_test 2024-03-28 21:12:46 +02:00
Peter Dimov
a09b9b2c5a Add bind_front_md_test 2024-03-28 21:12:46 +02:00
Peter Dimov
758b0c2ef9 Add bind_front_mfn_test 2024-03-28 21:12:46 +02:00
Peter Dimov
4ea967b756 Avoid bind_front_obj_test failure on GCC 4.8 2024-03-28 21:12:46 +02:00
Peter Dimov
d745abe3a3 Disable invoke_mfn_constexpr_test, invoke_md_constexpr_test for GCC 4.9 as well 2024-03-28 21:12:46 +02:00
Peter Dimov
fa9180b234 Add GCC 4.9 to GHA 2024-03-28 21:12:46 +02:00
Peter Dimov
abcc654046 Add bind_front_obj_test 2024-03-28 21:12:46 +02:00
Peter Dimov
b6deff5638 Update bind_front_fn_test 2024-03-28 21:12:46 +02:00
Peter Dimov
90e76cb4f4 Add bind_front 2024-03-28 21:12:45 +02:00
Peter Dimov
c290c03ea3 Merge branch 'master' into develop 2024-03-28 21:12:12 +02:00
Peter Dimov
bba8d5f101 Update CMakeLists.txt 2024-03-28 20:32:41 +02:00
Peter Dimov
56b776fc29 Update test/quick.cpp 2024-03-28 20:31:36 +02:00
Rene Rivera
0598dd0688 Sync from upstream. 2024-03-23 07:58:05 -05:00
Peter Dimov
53c5bcf824 Disable is_nothrow_invocable under msvc-14.0 2024-03-22 19:15:09 +02:00
Peter Dimov
e270914326 Rephrase is_nothrow_invocable to not crash MSVC 2024-03-22 19:05:04 +02:00
Peter Dimov
5b6c4ffe95 Add is_nothrow_invocable 2024-03-22 18:38:10 +02:00
Peter Dimov
26e18fd796 Add is_invocable 2024-03-22 18:14:36 +02:00
Peter Dimov
571b48ca51 Add Boost::mp11 to test/CMakeLists.txt 2024-03-22 17:48:08 +02:00
Peter Dimov
b4b6cacb9d Add invoke_result_t 2024-03-22 17:34:42 +02:00
Peter Dimov
6b0825b893 Disable invoke_mfn_constexpr_test and invoke_md_constexpr_test for GCC 4.8 2024-03-22 05:09:13 +02:00
Peter Dimov
dca886ef30 Add constexpr tests for invoke 2024-03-22 05:02:43 +02:00
Peter Dimov
4710db471a Add noexcept tests for invoke 2024-03-22 02:35:29 +02:00
Peter Dimov
d83085a5d9 Add trailing return types to mem_fn for C++11 2024-03-21 21:37:10 +02:00
Peter Dimov
8633042b73 Add constexpr to mem_fn and invoke 2024-03-21 21:30:10 +02:00
Peter Dimov
eba152aa8e Reimplement mem_fn 2024-03-21 21:27:04 +02:00
Peter Dimov
efff37c7a3 Add mem_fn_mfn_test, mem_fn_md_test 2024-03-21 21:00:34 +02:00
Peter Dimov
d745a4cfba Disable -Wnoexcept-type under GCC 7 2024-03-21 20:43:25 +02:00
Peter Dimov
9743e1e03f Add invoke_md_test 2024-03-21 20:28:27 +02:00
Peter Dimov
3980572c34 Add invoke_mfn_test 2024-03-21 20:21:58 +02:00
Peter Dimov
9cad6fbca9 Add invoke_obj_test 2024-03-21 20:12:01 +02:00
Peter Dimov
31fe10bf54 Update invoke_fn_test.cpp 2024-03-21 20:04:47 +02:00
Peter Dimov
b6858273bd Add boost::compat::invoke 2024-03-21 19:57:32 +02:00
Peter Dimov
0220855d9c Update ci.yml 2024-03-21 19:51:58 +02:00
Peter Dimov
91c2054151 Merge pull request #7 from cmazakas/missing-copyright
Add missing copyright to shared_lock_test.cpp
2024-03-21 19:48:13 +02:00
Christian Mazakas
6153916abe Add missing copyright to shared_lock_test.cpp 2024-03-21 10:41:17 -07:00
Rene Rivera
c511487e78 Make the library modular usable. 2024-03-11 08:27:02 -05:00
102 changed files with 12051 additions and 80 deletions

295
.drone.jsonnet Normal file
View File

@@ -0,0 +1,295 @@
# 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',
'uname -a',
'echo $DRONE_STAGE_MACHINE',
] +
(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 24.04 GCC 13 32/64",
"cppalliance/droneubuntu2404: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/64 ASAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b', ADDRMD: '32,64' } + asan,
"g++-14-multilib",
),
linux_pipeline(
"Linux 24.04 GCC 14 32/64 UBSAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b', ADDRMD: '32,64' } + ubsan,
"g++-14-multilib",
),
linux_pipeline(
"Linux 25.10 GCC 15 32/64",
"cppalliance/droneubuntu2510:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-15', CXXSTD: '11,14,17,20,23,2c', ADDRMD: '32,64' },
"g++-15-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 24.04 Clang 16",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-16', CXXSTD: '11,14,17,20,2b' },
"clang-16",
),
linux_pipeline(
"Linux 24.04 Clang 17",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '11,14,17,20,2b' },
"clang-17",
),
linux_pipeline(
"Linux 24.04 Clang 18",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '11,14,17,20,2b' },
"clang-18",
),
linux_pipeline(
"Linux 24.04 Clang 19",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-19', CXXSTD: '11,14,17,20,2b' },
"clang-19",
),
linux_pipeline(
"Linux 24.04 Clang 20 UBSAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-20', CXXSTD: '11,14,17,20,23,2c' } + ubsan,
"clang-20",
),
linux_pipeline(
"Linux 24.04 Clang 20 ASAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-20', CXXSTD: '11,14,17,20,23,2c' } + asan,
"clang-20",
),
linux_pipeline(
"Linux 25.10 Clang 21",
"cppalliance/droneubuntu2510:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-21', CXXSTD: '11,14,17,20,23,2c' },
"clang-21",
),
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",
),
macos_pipeline(
"MacOS 14 Xcode 16.2.0 UBSAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,17,20,2b' } + ubsan,
xcode_version = "16.2.0", osx_version = "sonoma", arch = "arm64",
),
macos_pipeline(
"MacOS 14 Xcode 16.2.0 ASAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,17,20,2b' } + asan,
xcode_version = "16.2.0", osx_version = "sonoma", 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,146 +19,216 @@ 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"
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"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: g++-7
- toolset: gcc-8
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: g++-8
- toolset: gcc-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
- toolset: gcc-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
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"
container: ubuntu:24.04
os: ubuntu-latest
container: ubuntu:23.04
install: g++-13
- toolset: gcc-14
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:24.04
os: ubuntu-latest
install: g++-14
- toolset: gcc-15
cxxstd: "03,11,14,17,20,23,2c"
container: ubuntu:25.04
os: ubuntu-latest
install: g++-15
- 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
cxxstd: "03,11,14,17"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-6.0
- toolset: clang
compiler: clang++-7
cxxstd: "03,11,14,17"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-7
- toolset: clang
compiler: clang++-8
cxxstd: "03,11,14,17"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-8
- toolset: clang
compiler: clang++-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-9
- toolset: clang
compiler: clang++-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-10
- toolset: clang
compiler: clang++-11
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-11
- toolset: clang
compiler: clang++-12
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-12
- toolset: clang
compiler: clang++-13
cxxstd: "03,11,14,17,20,2b"
os: ubuntu-22.04
container: ubuntu:22.04
os: ubuntu-latest
install: clang-13
- toolset: clang
compiler: clang++-14
cxxstd: "03,11,14,17,20,2b"
os: ubuntu-22.04
container: ubuntu:22.04
os: ubuntu-latest
install: clang-14
- toolset: clang
compiler: clang++-15
cxxstd: "03,11,14,17,20,2b"
os: ubuntu-22.04
container: ubuntu:22.04
os: ubuntu-latest
install: clang-15
- toolset: clang
compiler: clang++-16
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:24.04
os: ubuntu-latest
container: ubuntu:23.04
install: clang-16
- toolset: clang
cxxstd: "03,11,14,17,2a"
os: macos-11
compiler: clang++-17
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:24.04
os: ubuntu-latest
install: clang-17
- toolset: clang
compiler: clang++-18
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:24.04
os: ubuntu-latest
install: clang-18
- toolset: clang
compiler: clang++-19
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:24.04
os: ubuntu-latest
install: clang-19
- toolset: clang
compiler: clang++-20
cxxstd: "03,11,14,17,20,23,2c"
container: ubuntu:24.04
os: ubuntu-latest
install: clang-20
- toolset: clang
compiler: clang++-21
cxxstd: "03,11,14,17,20,23,2c"
container: ubuntu:25.10
os: ubuntu-latest
install: clang-21
- toolset: clang
cxxstd: "03,11,14,17,20,2b"
os: macos-12
os: macos-14
- toolset: clang
cxxstd: "03,11,14,17,20,2b"
os: macos-13
cxxstd: "03,11,14,17,20,23,2c"
os: macos-15
- toolset: clang
cxxstd: "03,11,14,17,20,23,2c"
os: macos-26
runs-on: ${{matrix.os}}
container: ${{matrix.container}}
container:
image: ${{matrix.container}}
volumes:
- /node20217:/node20217:rw,rshared
- ${{ startsWith(matrix.container, 'ubuntu:1') && '/node20217:/__e/node20:ro,rshared' || ' ' }}
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v3
- name: Setup container environment
if: matrix.container
run: |
apt-get update
apt-get -y install sudo python3 git g++
apt-get -y install sudo python3 git g++ curl xz-utils
- name: Install nodejs20glibc2.17
if: ${{ startsWith( matrix.container, 'ubuntu:1' ) }}
run: |
curl -LO https://archives.boost.io/misc/node/node-v20.9.0-linux-x64-glibc-217.tar.xz
tar -xf node-v20.9.0-linux-x64-glibc-217.tar.xz --strip-components 1 -C /node20217
ldd /__e/node20/bin/node
- uses: actions/checkout@v4
- name: Install packages
if: matrix.install
@@ -185,7 +255,7 @@ jobs:
mkdir -p libs/$LIBRARY
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python3 tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
python3 tools/boostdep/depinst/depinst.py $LIBRARY
./bootstrap.sh
./b2 -d0 headers
@@ -204,14 +274,6 @@ jobs:
fail-fast: false
matrix:
include:
- toolset: msvc-14.0
cxxstd: "14,latest"
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.2
cxxstd: "14,17,20,latest"
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.3
cxxstd: "14,17,20,latest"
addrmd: 32,64
@@ -223,12 +285,12 @@ jobs:
- toolset: gcc
cxxstd: "03,11,14,17,2a"
addrmd: 64
os: windows-2019
os: windows-2022
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup Boost
shell: cmd
@@ -263,16 +325,16 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-11
- os: macos-12
- os: macos-13
- os: ubuntu-24.04
- os: macos-14
- os: macos-15
- os: macos-26
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Install packages
if: matrix.install
@@ -312,16 +374,16 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-11
- os: macos-12
- os: macos-13
- os: ubuntu-24.04
- os: macos-14
- os: macos-15
- os: macos-26
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Install packages
if: matrix.install
@@ -371,16 +433,16 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-11
- os: macos-12
- os: macos-13
- os: ubuntu-24.04
- os: macos-14
- os: macos-15
- os: macos-26
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Install packages
if: matrix.install
@@ -428,13 +490,12 @@ jobs:
fail-fast: false
matrix:
include:
- os: windows-2019
- os: windows-2022
- os: windows-latest
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup Boost
shell: cmd
@@ -477,13 +538,12 @@ jobs:
fail-fast: false
matrix:
include:
- os: windows-2019
- os: windows-2022
- os: windows-latest
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup Boost
shell: cmd
@@ -544,13 +604,12 @@ jobs:
fail-fast: false
matrix:
include:
- os: windows-2019
- os: windows-2022
- os: windows-latest
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup Boost
shell: cmd

5
.gitignore vendored Normal file
View File

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

View File

@@ -15,6 +15,8 @@ target_include_directories(boost_compat INTERFACE include)
target_link_libraries(boost_compat
INTERFACE
Boost::assert
Boost::config
Boost::throw_exception
)
target_compile_features(boost_compat INTERFACE cxx_std_11)

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

@@ -17,8 +17,7 @@ https://www.boost.org/LICENSE_1_0.txt
include::compat/overview.adoc[]
include::compat/changelog.adoc[]
include::compat/latch.adoc[]
include::compat/shared_lock.adoc[]
include::compat/reference.adoc[]
include::compat/copyright.adoc[]
:leveloffset: -1

58
doc/compat/bind_back.adoc Normal file
View File

@@ -0,0 +1,58 @@
////
Copyright 2024 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
[#bind_back]
# <boost/compat/bind_back.hpp>
:idprefix: ref_bind_back_
## Description
The header `<boost/compat/bind_back.hpp>` implements the {cpp}20 function
`std::bind_back`.
`bind_back` is a limited variant of `std::bind`. It only supports binding
the last several parameters of a function object to specific argument values.
## Example
```
struct X
{
void f(int a, int b) const noexcept;
};
int main()
{
auto fn = boost::compat::bind_back(&X::f, 1, 2);
X x;
fn(x); // calls x.f(1, 2)
}
```
## Synopsis
```
namespace boost
{
namespace compat
{
template<class F, class... A> auto bind_back(F&& f, A&&... a);
} // namespace compat
} // namespace boost
```
## bind_back
```
template<class F, class... A> auto bind_back( F&& f, A&&... a );
```
[horizontal]
Returns:;; A function object `fn` such that `fn(b...)` is equivalent to
`invoke(f, b..., a...)`.

View File

@@ -0,0 +1,58 @@
////
Copyright 2024 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
[#bind_front]
# <boost/compat/bind_front.hpp>
:idprefix: ref_bind_front_
## Description
The header `<boost/compat/bind_front.hpp>` implements the {cpp}20 function
`std::bind_front`.
`bind_front` is a limited variant of `std::bind`. It only supports binding
the first several parameters of a function object to specific argument values.
## Example
```
struct X
{
void f(int a, int b) const noexcept;
};
int main()
{
X x;
auto fn = boost::compat::bind_front(&X::f, &x);
fn(1, 2); // calls x.f(1, 2)
}
```
## Synopsis
```
namespace boost
{
namespace compat
{
template<class F, class... A> auto bind_front(F&& f, A&&... a);
} // namespace compat
} // namespace boost
```
## bind_front
```
template<class F, class... A> auto bind_front(F&& f, A&&... a);
```
[horizontal]
Returns:;; A function object `fn` such that `fn(b...)` is equivalent to
`invoke(f, a..., b...)`.

View File

@@ -8,6 +8,23 @@ https://www.boost.org/LICENSE_1_0.txt
# Revision History
:idprefix: changelog_
## Changes in 1.90.0
* Added `to_underlying.hpp` (contributed by Braden Ganetsky.)
## Changes in 1.89.0
* Added `move_only_function.hpp`.
## Changes in 1.87.0
* Added `to_array.hpp` (contributed by Ruben Perez Hidalgo.)
## 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
* Added `latch.hpp`, an implementation of `std::latch` (contributed by Christian Mazakas.)

View File

@@ -8,6 +8,6 @@ https://www.boost.org/LICENSE_1_0.txt
# Copyright and License
:idprefix:
This documentation is copyright 2023 Peter Dimov and contributors and is
distributed under the
This documentation is copyright 2023, 2024 Peter Dimov and
contributors and is distributed under the
http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0].

View File

@@ -0,0 +1,205 @@
////
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).
Since `nontype_t` requires {cpp}17 as it has a template parameter of type `auto`, the constructors taking `nontype_t<f>` are only available under {cpp}17 or later.
## 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 expression-equivalent to `invoke_r<R>(f, call-args)`.
Example:;;
+
--
```cpp
struct point { int x = 1, y = 2; };
point p;
compat::function_ref<int(point const&)> f(compat::nontype<&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<&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<&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

@@ -0,0 +1,69 @@
////
Copyright 2024 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
[#integer_sequence]
# <boost/compat/integer_sequence.hpp>
:idprefix: ref_integer_sequence_
## Description
The header `<boost/compat/integer_sequence.hpp>` implements the {cpp}14 utilities
`std::integer_sequence`, `std::index_sequence`, `std::make_integer_sequence`,
`std::make_index_sequence`, and `std::index_sequence_for`.
## Synopsis
```
namespace boost
{
namespace compat
{
template<class T, T... I> struct integer_sequence;
template<class T, T N> using make_integer_sequence = /*...*/;
template<std::size_t... I> using index_sequence = /*...*/;
template<std::size_t N> using make_index_sequence = /*...*/;
template<class... T> using index_sequence_for = /*...*/;
} // namespace compat
} // namespace boost
```
## integer_sequence
```
template<class T, T... I> struct integer_sequence {};
```
## make_integer_sequence
```
template<class T, T N> using make_integer_sequence = /*...*/;
```
`make_integer_sequence<T, N>` is an alias for `integer_sequence<T, 0, 1, 2, ..., N-1>`.
## index_sequence
```
template<std::size_t... I> using index_sequence = integer_sequence<std::size_t, I...>;
```
## make_index_sequence
```
template<std::size_t N> using make_index_sequence = make_integer_sequence<std::size_t, N>;
```
## index_sequence_for
```
template<class... T> using index_sequence_for = make_integer_sequence<std::size_t, sizeof...(T)>;
```

130
doc/compat/invoke.adoc Normal file
View File

@@ -0,0 +1,130 @@
////
Copyright 2024 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
[#invoke]
# <boost/compat/invoke.hpp>
:idprefix: ref_invoke_
## Description
The header `<boost/compat/invoke.hpp>` implements the {cpp}17 function
`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
```
struct X
{
void f(int a, int b) const noexcept;
};
int main()
{
X x;
boost::compat::invoke(&X::f, x, 1, 2); // calls x.f(1, 2)
}
```
## Synopsis
```
namespace boost
{
namespace compat
{
template<class F, class... A> auto invoke(F&& f, A&&... a);
template<class F, class... A> using invoke_result_t = /*...*/;
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
```
## invoke
```
template<class F, class... A> auto invoke(F&& f, A&&... a) noexcept(/*...*/) -> /*...*/;
```
[horizontal]
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 return type is `decltype(r)`, and the `noexcept` clause is `noexcept(noexcept(r))`, where `r` is the return expression.
## invoke_result_t
```
template<class F, class... A> using invoke_result_t =
decltype( invoke(std::declval<F>(), std::declval<A>()...) );
```
## is_invocable
```
template<class F, class... A> struct is_invocable: public /*...*/;
```
The base class of `is_invocable<F, A...>` is `std::true_type` when `invoke(std::declval<F>(), std::declval<A>()...)` is a valid expression, `std::false_type` otherwise.
## is_nothrow_invocable
```
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,7 +6,7 @@ https://www.boost.org/LICENSE_1_0.txt
[#latch]
# <boost/compat/latch.hpp>
:idprefix: latch_
:idprefix: ref_latch_
## Description

67
doc/compat/mem_fn.adoc Normal file
View File

@@ -0,0 +1,67 @@
////
Copyright 2024 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
[#mem_fn]
# <boost/compat/mem_fn.hpp>
:idprefix: ref_mem_fn_
## Description
The header `<boost/compat/mem_fn.hpp>` implements the {cpp}11 function
`std::mem_fn`.
`mem_fn(pm)`, where `pm` is a pointer to member, returns a function object
that can be used to invoke the member function, or obtain a reference to the
data member, using a function call syntax.
Even though `std::mem_fn` is {cpp}11, later standards place stricter
requirements on the returned function object (it needs to be SFINAE friendly
and propagate `noexcept` correctly.) `boost::compat::mem_fn` implements
these stricter requirements.
## Example
```
struct X
{
void f(int a, int b) const noexcept;
};
int main()
{
auto fn = boost::compat::mem_fn(&X::f);
X x;
fn(x, 1, 2); // calls x.f(1, 2)
}
```
## Synopsis
```
namespace boost
{
namespace compat
{
template<class M, class T> auto mem_fn(M T::* pm) noexcept;
} // namespace compat
} // namespace boost
```
## mem_fn
```
template<class M, class T> auto mem_fn(M T::* pm) noexcept;
```
[horizontal]
Returns:;; A function object `fn` such that:
* `fn(x, a...)` is equivalent to `(x.*pm)(a...)`, when `M` is a function type and the type of `X` is `T` or derived from `T`;
* `fn(x, a...)` is equivalent to `((*x).*pm)(a...)`, when `M` is a function type and the type of `X` is not `T` or derived from `T`;
* `fn(x)` is equivalent to `x.*pm`, when `M` is an object type and the type of `X` is `T` or derived from `T`;
* `fn(x)` is equivalent to `(*x).*pm`, when `M` is an object type and the type of `X` is not `T` or derived from `T`.

View File

@@ -0,0 +1,252 @@
////
Copyright 2025 Christian Mazakas
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
[#move_only_function]
# <boost/compat/move_only_function.hpp>
:idprefix: ref_move_only_function_
## Description
The header `<boost/compat/move_only_function.hpp>` implements the {cpp}23 class https://en.cppreference.com/w/cpp/utility/functional/move_only_function.html[std::move_only_function].
`move_only_function` is a polymorphic wrapper that stores and manages a https://en.cppreference.com/w/cpp/named_req/Callable[Callable], only requiring that the type supports move construction and move assignment.
This is in contrast to the commonly used `std::function` which requires copyability of the underlying managed object.
`move_only_function` supports every combination of `const`, `noexcept` and reference qualification (none, `&`, `&&`).
## Example
```cpp
struct moveonly
{
std::unique_ptr<int> p_ = std::make_unique<int>( 1234 );
auto operator()( int x ) noexcept { return *p_ + x; }
};
boost::compat::move_only_function<int( int ) noexcept> f( moveonly{} );
std::cout << f( 4321 ) << std::endl;
```
## Synopsis
```cpp
namespace boost {
namespace compat {
template<class... S>
class move_only_function;
template< class T >
struct in_place_type_t { explicit in_place_type_t() = default; };
template<class R, class ...Args>
class move_only_function<R( Args... ) /* cv */ /* ref */ noexcept( /* noex */)>
{
move_only_function() noexcept;
move_only_function( std::nullptr_t ) noexcept;
template<class F>
move_only_function( F&& f );
template<class T, class ...CArgs>
explicit move_only_function( in_place_type_t<T>, CArgs&& ... args );
template<class T, class U, class ...CArgs>
explicit move_only_function( in_place_type_t<T>,
std::initializer_list<U> il, CArgs&& ... args );
move_only_function( move_only_function const& ) = delete;
move_only_function( move_only_function&& ) = default;
~move_only_function() = default;
move_only_function& operator=( move_only_function&& rhs );
move_only_function& operator=( std::nullptr_t ) noexcept;
template<class F> move_only_function& operator=( F&& f );
friend bool operator==( move_only_function const& fn, std::nullptr_t ) noexcept;
friend bool operator!=( move_only_function const& fn, std::nullptr_t ) noexcept;
void swap( move_only_function& rhs ) noexcept;
friend void swap( move_only_function& lhs, move_only_function& rhs ) noexcept;
explicit operator bool() const noexcept;
R operator()( Args... args ) /* cv */ /* ref */ noexcept( /* noex */ );
};
} // namespace compat
} // namespace boost
```
## Constructors
### Default Constructor
```cpp
move_only_function() noexcept;
```
[horizontal]
Effects::
Constructs an empty `move_only_function` which manages no object.
### Null Constructor
```cpp
move_only_function( std::nullptr_t ) noexcept;
```
[horizontal]
Effects::
Explicitly constructs an empty `move_only_function` using a nullptr value. Equivalent to default construction.
### Object Constructor
```cpp
template<class F>
move_only_function( F&& f );
```
[horizontal]
Effects:;; Given `using VT = decay_t<F>`, directly constructs an instance of `VT` using `forward<F>(f)` and stores it as the target object. +
+
If `F` is an empty function pointer, pointer-to-member or specialization of `move_only_function` then the constructed `move_only_function` is empty.
Constraints:;;
+
--
* `remove_cv_ref<F>` is not the same type as `move_only_function`
* `remove_cv_ref<F>` is not a specialization of `in_place_type_t`
* `VT` must be callable with the provided cvref qualifiers and the provided argument types
--
### In-Place Constructor
```cpp
template<class T, class ...CArgs>
explicit move_only_function( in_place_type_t<T>, CArgs&& ... args );
```
[horizontal]
Effects:;; Constructs an object of type `T` using the provided args directly, storing it as the target object.
Constraints:;;
+
--
* `is_constructible_v<T, CArgs...>` must be true
* `T` must be callable with the provided cvref qualifiers and the provided argument types
--
### List In-Place Constructor
```cpp
template<class T, class U, class ...CArgs>
explicit move_only_function( in_place_type_t<T>,
std::initializer_list<U> il, CArgs&& ... args );
```
[horizontal]
Effects:;; Constructs an object of type `T` using the provided initializer_list and args directly, storing it as the target Callable.
Constraints:;;
+
--
* `is_constructible_v<T, std::initializer_list<U>&, CArgs...>` must be true
* `T` must be callable with the provided cvref qualifiers and the provided argument types
--
### Move Constructor
```cpp
move_only_function( move_only_function&& f ) = default;
```
[horizontal]
Effects::
Tranfers ownership of the object managed by `f` to `*this`. After this operation completes, `f` is empty and manages no object.
## Assignment
### Move Assignment
```cpp
move_only_function& operator=( move_only_function&& rhs );
```
[horizontal]
Effects:;; Releases the currently managed object and takes ownership of the object managed by `rhs`, if applicable.
`rhs` is empty after move.
### Null Assigment
```cpp
move_only_function& operator=( std::nullptr_t ) noexcept;
```
[horizontal]
Effects:;; Releases the currently managed object, if applicable.
### Callable Assignment
```cpp
template<class F> move_only_function& operator=( F&& f );
```
[horizontal]
Effects:;; Releases the currently managed object and then does the equivalent of: `move_only_function(std::forward<F>(f)).swap(*this)`.
## Utility
### Null Equality
```cpp
friend bool operator==( move_only_function const& fn, std::nullptr_t ) noexcept;
friend bool operator!=( move_only_function const& fn, std::nullptr_t ) noexcept;
```
[horizontal]
Effects:;; Returns whether or not `fn` contains a target object.
### Swap
```cpp
void swap( move_only_function& rhs ) noexcept;
friend void swap( move_only_function& lhs, move_only_function& rhs ) noexcept;
```
[horizontal]
Effects:;; Exchanges the managed objects.
## Invocation
### Boolean Conversion
```cpp
explicit operator bool() const noexcept;
```
[horizontal]
Effects:;; Returns `true` if `*this` is managing an object, or `false` if `*this` is empty.
### Call Operator
```cpp
R operator()( Args... args ) /* cv */ /* ref */ noexcept( /* noex */ );
```
[horizontal]
Preconditions:;; `*this` currently manages an object.
Effects:;; Invokes the underlying target object. Equivalent to:
+
--
```cpp
return INVOKE<R>(static_cast<F inv-quals>(f), std::forward<Args>(args)...);
```
where `f` is the target object, and _inv-quals_ is defined by the standard:
* If _ref_ is empty, let _inv-quals_ be _cv&_,
* otherwise, let _inv-quals_ be _cv ref_.
--

58
doc/compat/nontype.adoc Normal file
View File

@@ -0,0 +1,58 @@
////
Copyright 2025 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
[#nontype]
# <boost/compat/nontype.hpp>
:idprefix: ref_nontype_
## Description
The header `<boost/compat/nontype.hpp>` provides the {cpp}26 variable
template `std::nontype`.
`nontype` is used for passing function pointers or member function
pointers to `function_ref`.
Since `nontype_t` and `nontype` have a template parameter of type
`auto`, they require {cpp}17. When {cpp}17 isn't available, this
header can still be included, but doesn't define them. (It would
have caused an error if it did.)
## Example
```
struct X
{
void f(int a, int b) const noexcept;
};
int main()
{
X x;
auto fnref = function_ref<void(int, int)>(nontype<&X::f>, &x);
fnref(1, 2); // calls x.f(1, 2)
}
```
## Synopsis
```
namespace boost
{
namespace compat
{
template<auto V> struct nontype_t
{
explicit nontype_t() = default;
};
template<auto V> inline constexpr nontype_t<V> nontype {};
} // namespace compat
} // namespace boost
```

18
doc/compat/reference.adoc Normal file
View File

@@ -0,0 +1,18 @@
////
Copyright 2024 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
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[]
include::mem_fn.adoc[]
include::move_only_function.adoc[]
include::shared_lock.adoc[]
include::to_array.adoc[]
include::to_underlying.adoc[]
include::type_traits.adoc[]

View File

@@ -6,7 +6,7 @@ https://www.boost.org/LICENSE_1_0.txt
[#shared_lock]
# <boost/compat/shared_lock.hpp>
:idprefix: shared_lock_
:idprefix: ref_shared_lock_
## Description
@@ -129,7 +129,7 @@ shared_lock( mutex_type& m, std::adopt_lock_t );
[horizontal]
Preconditions:;; `m` must be held by a previous call to `m.lock_shared()` or a
successful call to `m.try_lock_shared()`.
PostConditions:;; `mutex() == std::addressof(m)` and `owns_lock() == true`.
Postconditions:;; `mutex() == std::addressof(m)` and `owns_lock() == true`.
### Copy Constructor

72
doc/compat/to_array.adoc Normal file
View File

@@ -0,0 +1,72 @@
////
Copyright 2024 Ruben Perez Hidalgo
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
[#to_array]
# <boost/compat/to_array.hpp>
:idprefix: ref_to_array_
## Description
The header `<boost/compat/to_array.hpp>` implements, in a portable way, the C++20
`std::to_array` function, present in the `<array>` header.
`to_array` creates a `std::array` from a single-dimensional C array,
performing an element-wise copy or move.
## Example
```cpp
int input [] = {1, 2, 3};
std::array<int, 3> output = boost::compat::to_array(input);
assert((
output == std::array<int, 3>{{1, 2, 3}}
));
```
## Synopsis
```cpp
namespace boost
{
namespace compat
{
template <class T, std::size_t N>
constexpr std::array<remove_cv_t<T>, N> to_array(T (&a)[N]);
template <class T, std::size_t N>
constexpr std::array<remove_cv_t<T>, N> to_array(T (&&a)[N]);
} // namespace compat
} // namespace boost
```
## to_array
```cpp
template <class T, std::size_t N>
constexpr std::array<remove_cv_t<T>, N> to_array(T (&&a)[N]);
```
[horizontal]
Effects:;; Creates an array of `N` elements by copying elements in `a`.
For every `i` in `0, ..., N-1`, copy-initializes the i-th element
in the output array from `a[i]`.
Type requirements:;; `std::is_constructible_v<remove_cv_t<T>, T&> && !std::is_array_v<T>`.
Otherwise, the overload is ill-formed.
```cpp
template <class T, std::size_t N>
constexpr std::array<remove_cv_t<T>, N> to_array(T (&a)[N]);
```
[horizontal]
Effects:;; Creates an array of `N` elements by moving elements in `a`.
For every `i` in `0, ..., N-1`, move-initializes the i-th element
in the output array from `std::move(a[i])`.
Type requirements:;; `std::is_constructible_v<remove_cv_t<T>, T&&> && !std::is_array_v<T>`.
Otherwise, the overload is ill-formed.

View File

@@ -0,0 +1,57 @@
////
Copyright 2025 Braden Ganetsky
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
[#to_underlying]
# <boost/compat/to_underlying.hpp>
:idprefix: ref_to_underlying_
## Description
The header `<boost/compat/to_underlying.hpp>` implements the {cpp}23 function https://en.cppreference.com/w/cpp/utility/to_underlying.html[std::to_underlying].
`to_underlying` is a terse way of converting a value of enumeration type to its underlying type, avoiding accidental narrowing or widening. This function is ill-formed if the given value is not of enumeration type.
## Example
```cpp
enum e : std::uint16_t
{
e_value = 5
};
auto output = boost::compat::to_underlying(e_value);
static_assert(std::is_same<decltype(output), std::uint16_t>::value);
assert((
output == 5
));
```
## Synopsis
```cpp
namespace boost
{
namespace compat
{
template <class E>
constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept;
} // namespace compat
} // namespace boost
```
## to_underlying
```cpp
template <class E>
constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept;
```
[horizontal]
Effects:;; Casts the value `e` of enumeration type `E` to its underlying type.
Equivalent to `static_cast<typename std::underlying_type<E>::type>(e)`.
Type requirements:;; `std::is_enum<E>::value`.
Otherwise, the function is ill-formed.

View File

@@ -0,0 +1,45 @@
////
Copyright 2024 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
[#type_traits]
# <boost/compat/type_traits.hpp>
:idprefix: ref_type_traits_
## Description
The header `<boost/compat/type_traits.hpp>` implements some of the
post-{cpp}11 additions to the standard header `<type_traits>`.
## Synopsis
```
#include <type_traits>
namespace boost
{
namespace compat
{
template<class T> using remove_const_t = typename std::remove_const<T>::type;
template<class T> using remove_cv_t = typename std::remove_cv<T>::type;
template<class T> using remove_reference_t = typename std::remove_reference<T>::type;
template<class T> using remove_cvref_t = remove_cv_t<remove_reference_t<T>>;
template<class T> using decay_t = typename std::decay<T>::type;
template<bool B, class T = void> using enable_if_t = typename std::enable_if<B, T>::type;
template<bool B, class T, class F> using conditional_t = typename std::conditional<B, T, F>::type;
template<class... T> using void_t = void;
} // namespace compat
} // namespace boost
```

View File

@@ -0,0 +1,72 @@
#ifndef BOOST_COMPAT_BIND_BACK_HPP_INCLUDED
#define BOOST_COMPAT_BIND_BACK_HPP_INCLUDED
// Copyright 2024 Peter Dimov
// 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 <boost/compat/integer_sequence.hpp>
#include <boost/compat/detail/returns.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <tuple>
#include <utility>
namespace boost {
namespace compat {
namespace detail {
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
# pragma warning(push)
# pragma warning(disable: 4100) // 'a': unreferenced formal parameter
#endif
template<class F, class A, class... B, std::size_t... I>
static constexpr auto invoke_bind_back_( F&& f, A&& a, index_sequence<I...>, B&&... b )
BOOST_COMPAT_RETURNS( compat::invoke( std::forward<F>(f), std::forward<B>(b)..., std::get<I>( std::forward<A>(a) )... ) )
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
# pragma warning(pop)
#endif
template<class F, class... A> class bind_back_
{
private:
F f_;
std::tuple<A...> a_;
public:
template<class F2, class... A2>
constexpr bind_back_( F2&& f2, A2&&... a2 ): f_( std::forward<F2>(f2) ), a_( std::forward<A2>(a2)... ) {}
public:
template<class... B> BOOST_CXX14_CONSTEXPR auto operator()( B&&... b ) &
BOOST_COMPAT_RETURNS( detail::invoke_bind_back_( f_, a_, make_index_sequence<sizeof...(A)>(), std::forward<B>(b)... ) )
template<class... B> constexpr auto operator()( B&&... b ) const &
BOOST_COMPAT_RETURNS( detail::invoke_bind_back_( f_, a_, make_index_sequence<sizeof...(A)>(), std::forward<B>(b)... ) )
template<class... B> BOOST_CXX14_CONSTEXPR auto operator()( B&&... b ) &&
BOOST_COMPAT_RETURNS( detail::invoke_bind_back_( std::move(f_), std::move(a_), make_index_sequence<sizeof...(A)>(), std::forward<B>(b)... ) )
template<class... B> constexpr auto operator()( B&&... b ) const &&
BOOST_COMPAT_RETURNS( detail::invoke_bind_back_( std::move(f_), std::move(a_), make_index_sequence<sizeof...(A)>(), std::forward<B>(b)... ) )
};
} // namespace detail
template<class F, class... A> constexpr auto bind_back( F&& f, A&&... a ) -> detail::bind_back_< decay_t<F>, decay_t<A>... >
{
return { std::forward<F>(f), std::forward<A>(a)... };
}
} // namespace compat
} // namespace boost
#endif // BOOST_COMPAT_BIND_BACK_HPP_INCLUDED

View File

@@ -0,0 +1,72 @@
#ifndef BOOST_COMPAT_BIND_FRONT_HPP_INCLUDED
#define BOOST_COMPAT_BIND_FRONT_HPP_INCLUDED
// Copyright 2024 Peter Dimov
// 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 <boost/compat/integer_sequence.hpp>
#include <boost/compat/detail/returns.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <tuple>
#include <utility>
namespace boost {
namespace compat {
namespace detail {
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
# pragma warning(push)
# pragma warning(disable: 4100) // 'a': unreferenced formal parameter
#endif
template<class F, class A, class... B, std::size_t... I>
static constexpr auto invoke_bind_front_( F&& f, A&& a, index_sequence<I...>, B&&... b )
BOOST_COMPAT_RETURNS( compat::invoke( std::forward<F>(f), std::get<I>( std::forward<A>(a) )..., std::forward<B>(b)... ) )
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
# pragma warning(pop)
#endif
template<class F, class... A> class bind_front_
{
private:
F f_;
std::tuple<A...> a_;
public:
template<class F2, class... A2>
constexpr bind_front_( F2&& f2, A2&&... a2 ): f_( std::forward<F2>(f2) ), a_( std::forward<A2>(a2)... ) {}
public:
template<class... B> BOOST_CXX14_CONSTEXPR auto operator()( B&&... b ) &
BOOST_COMPAT_RETURNS( detail::invoke_bind_front_( f_, a_, make_index_sequence<sizeof...(A)>(), std::forward<B>(b)... ) )
template<class... B> constexpr auto operator()( B&&... b ) const &
BOOST_COMPAT_RETURNS( detail::invoke_bind_front_( f_, a_, make_index_sequence<sizeof...(A)>(), std::forward<B>(b)... ) )
template<class... B> BOOST_CXX14_CONSTEXPR auto operator()( B&&... b ) &&
BOOST_COMPAT_RETURNS( detail::invoke_bind_front_( std::move(f_), std::move(a_), make_index_sequence<sizeof...(A)>(), std::forward<B>(b)... ) )
template<class... B> constexpr auto operator()( B&&... b ) const &&
BOOST_COMPAT_RETURNS( detail::invoke_bind_front_( std::move(f_), std::move(a_), make_index_sequence<sizeof...(A)>(), std::forward<B>(b)... ) )
};
} // namespace detail
template<class F, class... A> constexpr auto bind_front( F&& f, A&&... a ) -> detail::bind_front_< decay_t<F>, decay_t<A>... >
{
return { std::forward<F>(f), std::forward<A>(a)... };
}
} // namespace compat
} // namespace boost
#endif // BOOST_COMPAT_BIND_FRONT_HPP_INCLUDED

View File

@@ -0,0 +1,37 @@
#ifndef BOOST_COMPAT_NONTYPE_HPP_INCLUDED
#define BOOST_COMPAT_NONTYPE_HPP_INCLUDED
// Copyright 2024 Christian Mazakas
// Copyright 2025 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/config.hpp>
namespace boost {
namespace compat {
namespace detail {
template<class V, V v> struct nttp_holder
{
};
} // namespace detail
#if defined(__cpp_nontype_template_parameter_auto) && __cpp_nontype_template_parameter_auto >= 201606L
template<auto V> struct nontype_t: public detail::nttp_holder<decltype(V), V>
{
explicit nontype_t() = default;
};
template<auto V>
BOOST_INLINE_CONSTEXPR nontype_t<V> nontype {};
#endif
} // namespace compat
} // namespace boost
#endif // BOOST_COMPAT_NONTYPE_HPP_INCLUDED

View File

@@ -0,0 +1,10 @@
#ifndef BOOST_COMPAT_DETAIL_RETURNS_HPP_INCLUDED
#define BOOST_COMPAT_DETAIL_RETURNS_HPP_INCLUDED
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#define BOOST_COMPAT_RETURNS(...) noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) { return __VA_ARGS__; }
#endif // BOOST_COMPAT_DETAIL_RETURNS_HPP_INCLUDED

View File

@@ -0,0 +1,278 @@
#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/detail/nontype.hpp>
#include <boost/compat/invoke.hpp>
#include <boost/compat/type_traits.hpp>
#include <type_traits>
#include <utility>
namespace boost {
namespace compat {
template <class... S>
struct function_ref;
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)...);
}
};
template <class F, F 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 <class F, F 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 <class F, F 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)...);
}
};
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)));
}
template <class F, F f>
function_ref_base(mem_fn_tag, nttp_holder<F, f>)
: thunk_{}, invoke_(&invoke_mem_fn_holder<F, f, Const, NoEx, R, Args...>::invoke_mem_fn) {
thunk_.pobj_ = nullptr;
}
template <class F, F f, class U>
function_ref_base(mem_fn_tag, nttp_holder<F, 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 <class F, F f, class T>
function_ref_base(mem_fn_tag, nttp_holder<F, 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));
}
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) {}
template <class F, F f, enable_if_t<is_invocable_using<F>::value, int> = 0>
function_ref(detail::nttp_holder<F, f> x) noexcept : base_type(mem_fn_tag{}, x) {}
template <class F, F f, class U, class T = remove_reference_t<U>,
enable_if_t<!std::is_rvalue_reference<U&&>::value && is_invocable_using<F, T&>::value, int> = 0>
function_ref(detail::nttp_holder<F, f> x, U&& obj) noexcept : base_type(mem_fn_tag{}, x, std::forward<U>(obj)) {}
template <class F, F f, class T, enable_if_t<is_invocable_using<F, T*>::value, int> = 0>
function_ref(detail::nttp_holder<F, f> x, T* obj) noexcept : base_type(mem_fn_tag{}, x, obj) {}
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) {}
template <class F, F f, enable_if_t<is_invocable_using<F>::value, int> = 0>
function_ref(detail::nttp_holder<F, f> x) noexcept : base_type(mem_fn_tag{}, x) {}
template <class F, F f, class U, class T = remove_reference_t<U>,
enable_if_t<!std::is_rvalue_reference<U&&>::value && is_invocable_using<F, T const&>::value, int> = 0>
function_ref(detail::nttp_holder<F, f> x, U&& obj) noexcept : base_type(mem_fn_tag{}, x, std::forward<U>(obj)) {}
template <class F, F f, class T, enable_if_t<is_invocable_using<F, T const*>::value, int> = 0>
function_ref(detail::nttp_holder<F, f> x, T const* obj) noexcept : base_type(mem_fn_tag{}, x, obj) {}
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) {}
template <class F, F f, enable_if_t<is_invocable_using<F>::value, int> = 0>
function_ref(detail::nttp_holder<F, f> x) noexcept : base_type(mem_fn_tag{}, x) {}
template <class F, F f, class U, class T = remove_reference_t<U>,
enable_if_t<!std::is_rvalue_reference<U&&>::value && is_invocable_using<F, T&>::value, int> = 0>
function_ref(detail::nttp_holder<F, f> x, U&& obj) noexcept : base_type(mem_fn_tag{}, x, std::forward<U>(obj)) {}
template <class F, F f, class T, enable_if_t<is_invocable_using<F, T*>::value, int> = 0>
function_ref(detail::nttp_holder<F, f> x, T* obj) noexcept : base_type(mem_fn_tag{}, x, obj) {}
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) {}
template <class F, F f, enable_if_t<is_invocable_using<F>::value, int> = 0>
function_ref(detail::nttp_holder<F, f> x) noexcept : base_type(mem_fn_tag{}, x) {}
template <class F, F f, class U, class T = remove_reference_t<U>,
enable_if_t<!std::is_rvalue_reference<U&&>::value && is_invocable_using<F, T const&>::value, int> = 0>
function_ref(detail::nttp_holder<F, f> x, U&& obj) noexcept : base_type(mem_fn_tag{}, x, std::forward<U>(obj)) {}
template <class F, F f, class T, enable_if_t<is_invocable_using<F, T const*>::value, int> = 0>
function_ref(detail::nttp_holder<F, f> x, T const* obj) noexcept : base_type(mem_fn_tag{}, x, obj) {}
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

@@ -0,0 +1,120 @@
#ifndef BOOST_COMPAT_INTEGER_SEQUENCE_HPP_INCLUDED
#define BOOST_COMPAT_INTEGER_SEQUENCE_HPP_INCLUDED
// Copyright 2015, 2017, 2019 Peter Dimov.
//
// Distributed under the Boost Software License, Version 1.0.
//
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
#include <cstddef>
#if defined(_MSC_VER) || defined(__GNUC__)
# pragma push_macro( "I" )
# undef I
#endif
#if defined(__has_builtin)
# if __has_builtin(__make_integer_seq)
# define BOOST_COMPAT_HAS_MAKE_INTEGER_SEQ
# endif
#endif
namespace boost
{
namespace compat
{
// integer_sequence
template<class T, T... I> struct integer_sequence
{
};
#if defined(BOOST_COMPAT_HAS_MAKE_INTEGER_SEQ)
template<class T, T N> using make_integer_sequence = __make_integer_seq<integer_sequence, T, N>;
#else
// detail::make_integer_sequence_impl
namespace detail
{
// iseq_if_c
template<bool C, class T, class E> struct iseq_if_c_impl;
template<class T, class E> struct iseq_if_c_impl<true, T, E>
{
using type = T;
};
template<class T, class E> struct iseq_if_c_impl<false, T, E>
{
using type = E;
};
template<bool C, class T, class E> using iseq_if_c = typename iseq_if_c_impl<C, T, E>::type;
// iseq_identity
template<class T> struct iseq_identity
{
using type = T;
};
template<class S1, class S2> struct append_integer_sequence;
template<class T, T... I, T... J> struct append_integer_sequence<integer_sequence<T, I...>, integer_sequence<T, J...>>
{
using type = integer_sequence< T, I..., ( J + sizeof...(I) )... >;
};
template<class T, T N> struct make_integer_sequence_impl;
template<class T, T N> struct make_integer_sequence_impl_
{
private:
static_assert( N >= 0, "make_integer_sequence<T, N>: N must not be negative" );
static T const M = N / 2;
static T const R = N % 2;
using S1 = typename make_integer_sequence_impl<T, M>::type;
using S2 = typename append_integer_sequence<S1, S1>::type;
using S3 = typename make_integer_sequence_impl<T, R>::type;
using S4 = typename append_integer_sequence<S2, S3>::type;
public:
using type = S4;
};
template<class T, T N> struct make_integer_sequence_impl: iseq_if_c<N == 0, iseq_identity<integer_sequence<T>>, iseq_if_c<N == 1, iseq_identity<integer_sequence<T, 0>>, make_integer_sequence_impl_<T, N> > >
{
};
} // namespace detail
// make_integer_sequence
template<class T, T N> using make_integer_sequence = typename detail::make_integer_sequence_impl<T, N>::type;
#endif // defined(BOOST_COMPAT_HAS_MAKE_INTEGER_SEQ)
// index_sequence
template<std::size_t... I> using index_sequence = integer_sequence<std::size_t, I...>;
// make_index_sequence
template<std::size_t N> using make_index_sequence = make_integer_sequence<std::size_t, N>;
// index_sequence_for
template<class... T> using index_sequence_for = make_integer_sequence<std::size_t, sizeof...(T)>;
} // namespace compat
} // namespace boost
#if defined(_MSC_VER) || defined(__GNUC__)
# pragma pop_macro( "I" )
#endif
#endif // #ifndef BOOST_COMPAT_INTEGER_SEQUENCE_HPP_INCLUDED

View File

@@ -0,0 +1,119 @@
#ifndef BOOST_COMPAT_INVOKE_HPP_INCLUDED
#define BOOST_COMPAT_INVOKE_HPP_INCLUDED
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/mem_fn.hpp>
#include <boost/compat/type_traits.hpp>
#include <boost/compat/detail/returns.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <utility>
namespace boost {
namespace compat {
// invoke
template<class F, class... A>
constexpr auto invoke( F&& f, A&&... a )
BOOST_COMPAT_RETURNS( std::forward<F>(f)(std::forward<A>(a)...) )
template<class M, class T, class... A>
constexpr auto invoke( M T::* pm, A&&... a )
BOOST_COMPAT_RETURNS( compat::mem_fn(pm)(std::forward<A>(a)...) )
// invoke_result_t
template<class F, class... A> using invoke_result_t = decltype( compat::invoke( std::declval<F>(), std::declval<A>()... ) );
// is_invocable
namespace detail {
template<class, class F, class... A> struct is_invocable_: std::false_type {};
template<class F, class... A> struct is_invocable_< void_t<invoke_result_t<F, A...>>, F, A... >: std::true_type {};
} // namespace detail
template<class F, class... A> struct is_invocable: detail::is_invocable_<void, F, A...> {};
// is_nothrow_invocable
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
template<class F, class... A> struct is_nothrow_invocable: std::false_type {};
#else
namespace detail {
template<class F, class... A> struct is_nothrow_invocable_
{
using type = std::integral_constant<bool, noexcept( compat::invoke( std::declval<F>(), std::declval<A>()... ) )>;
};
} // namespace detail
template<class F, class... A> struct is_nothrow_invocable: conditional_t< is_invocable<F, A...>::value, detail::is_nothrow_invocable_<F, A...>, std::false_type >::type {};
#endif
// invoke_r
template<class R, class F, class... A, class En = enable_if_t<
std::is_void<R>::value && is_invocable<F, A...>::value >>
constexpr R invoke_r( F&& f, A&&... a )
noexcept( noexcept( static_cast<R>( compat::invoke( std::forward<F>(f), std::forward<A>(a)... ) ) ) )
{
return static_cast<R>( compat::invoke( std::forward<F>(f), std::forward<A>(a)... ) );
}
template<class R, class F, class... A, class = void, class En = enable_if_t<
!std::is_void<R>::value && std::is_convertible< invoke_result_t<F, A...>, R >::value >>
constexpr R invoke_r( F&& f, A&&... a )
noexcept( noexcept( static_cast<R>( compat::invoke( std::forward<F>(f), std::forward<A>(a)... ) ) ) )
{
return compat::invoke( std::forward<F>(f), std::forward<A>(a)... );
}
// is_invocable_r
namespace detail {
template<class R, class F, class... A> struct is_invocable_r_: std::is_convertible< invoke_result_t<F, A...>, R > {};
} // namespace detail
template<class R, class F, class... A> struct is_invocable_r:
conditional_t< !is_invocable<F, A...>::value, std::false_type,
conditional_t< std::is_void<R>::value, std::true_type,
detail::is_invocable_r_<R, F, A...> >> {};
// is_nothrow_invocable_r
#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
template<class R, class F, class... A> struct is_nothrow_invocable_r: std::false_type {};
#else
namespace detail {
template<class R, class F, class... A> struct is_nothrow_invocable_r_
{
using type = std::integral_constant<bool, noexcept( compat::invoke_r<R>( std::declval<F>(), std::declval<A>()... ) )>;
};
} // namespace detail
template<class R, class F, class... A> struct is_nothrow_invocable_r: conditional_t< is_invocable_r<R, F, A...>::value, detail::is_nothrow_invocable_r_<R, F, A...>, std::false_type >::type {};
#endif
} // namespace compat
} // namespace boost
#endif // BOOST_COMPAT_INVOKE_HPP_INCLUDED

View File

@@ -0,0 +1,78 @@
#ifndef BOOST_COMPAT_MEM_FN_HPP_INCLUDED
#define BOOST_COMPAT_MEM_FN_HPP_INCLUDED
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/type_traits.hpp>
#include <boost/compat/detail/returns.hpp>
#include <functional>
namespace boost {
namespace compat {
namespace detail {
template<class T, class U, class Td = remove_cvref_t<T>, class Ud = remove_cvref_t<U>>
struct is_same_or_base: std::integral_constant<bool, std::is_same<Td, Ud>::value || std::is_base_of<Td, Ud>::value>
{
};
template<class T> struct is_reference_wrapper_: std::false_type {};
template<class T> struct is_reference_wrapper_< std::reference_wrapper<T> >: std::true_type {};
template<class T> struct is_reference_wrapper: is_reference_wrapper_< remove_cvref_t<T> > {};
template<class M, class T> struct _mfn
{
M T::* pm_;
template<class U, class... A, class En = enable_if_t<is_same_or_base<T, U>::value>>
constexpr auto operator()( U&& u, A&&... a ) const
BOOST_COMPAT_RETURNS( (std::forward<U>(u).*pm_)( std::forward<A>(a)... ) )
template<class U, class... A, class = void, class En = enable_if_t< !is_same_or_base<T, U>::value && is_reference_wrapper<U>::value>>
constexpr auto operator()( U&& u, A&&... a ) const
BOOST_COMPAT_RETURNS( (u.get().*pm_)( std::forward<A>(a)... ) )
template<class U, class... A, class = void, class = void, class En = enable_if_t< !is_same_or_base<T, U>::value && !is_reference_wrapper<U>::value>>
constexpr auto operator()( U&& u, A&&... a ) const
BOOST_COMPAT_RETURNS( ((*std::forward<U>(u)).*pm_)( std::forward<A>(a)... ) )
};
template<class M, class T> struct _md
{
M T::* pm_;
template<class U, class En = enable_if_t<is_same_or_base<T, U>::value>>
constexpr auto operator()( U&& u ) const
BOOST_COMPAT_RETURNS( std::forward<U>(u).*pm_ )
template<class U, class = void, class En = enable_if_t< !is_same_or_base<T, U>::value && is_reference_wrapper<U>::value>>
constexpr auto operator()( U&& u ) const
BOOST_COMPAT_RETURNS( u.get().*pm_ )
template<class U, class = void, class = void, class En = enable_if_t< !is_same_or_base<T, U>::value && !is_reference_wrapper<U>::value>>
constexpr auto operator()( U&& u ) const
BOOST_COMPAT_RETURNS( (*std::forward<U>(u)).*pm_ )
};
} // namespace detail
template<class M, class T, class En = enable_if_t< std::is_function<M>::value > >
constexpr auto mem_fn( M T::* pm ) noexcept -> detail::_mfn<M, T>
{
return detail::_mfn<M, T>{ pm };
}
template<class M, class T, class = void, class En = enable_if_t< !std::is_function<M>::value > >
constexpr auto mem_fn( M T::* pm ) noexcept -> detail::_md<M, T>
{
return detail::_md<M, T>{ pm };
}
} // namespace compat
} // namespace boost
#endif // BOOST_COMPAT_MEM_FN_HPP_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,60 @@
#ifndef BOOST_COMPAT_TO_ARRAY_HPP_INCLUDED
#define BOOST_COMPAT_TO_ARRAY_HPP_INCLUDED
// Copyright 2024 Ruben Perez Hidalgo
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/integer_sequence.hpp>
#include <boost/compat/type_traits.hpp>
#include <array>
#include <cstddef>
#include <type_traits>
#include <utility>
namespace boost {
namespace compat {
namespace detail {
template <class T, std::size_t N, std::size_t... I>
constexpr std::array<remove_cv_t<T>, N> to_array_lvalue(T (&a)[N], index_sequence<I...>)
{
return {{a[I]...}};
}
template <class T, std::size_t N, std::size_t... I>
constexpr std::array<remove_cv_t<T>, N> to_array_rvalue(T (&&a)[N], index_sequence<I...>)
{
return {{std::move(a[I])...}};
}
} // namespace detail
template <class T, std::size_t N>
constexpr std::array<remove_cv_t<T>, N> to_array(T (&a)[N])
{
static_assert(
std::is_constructible<remove_cv_t<T>, T&>::value,
"This overload requires the resulting element type to be constructible from T&"
);
static_assert(!std::is_array<T>::value, "to_array does not work for multi-dimensional C arrays");
return detail::to_array_lvalue(a, make_index_sequence<N>{});
}
template <class T, std::size_t N>
constexpr std::array<remove_cv_t<T>, N> to_array(T (&&a)[N])
{
static_assert(
std::is_constructible<remove_cv_t<T>, T&&>::value,
"This overload requires the resulting element type to be constructible from T&&"
);
static_assert(!std::is_array<T>::value, "to_array does not work for multi-dimensional C arrays");
return detail::to_array_rvalue(static_cast<T(&&)[N]>(a), make_index_sequence<N>{});
}
} // namespace compat
} // namespace boost
#endif // BOOST_COMPAT_TO_ARRAY_HPP_INCLUDED

View File

@@ -0,0 +1,22 @@
#ifndef BOOST_COMPAT_TO_UNDERLYING_HPP_INCLUDED
#define BOOST_COMPAT_TO_UNDERLYING_HPP_INCLUDED
// Copyright 2025 Braden Ganetsky
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <type_traits>
namespace boost {
namespace compat {
template <class E>
constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept
{
return static_cast<typename std::underlying_type<E>::type>(e);
}
} // namespace compat
} // namespace boost
#endif // BOOST_COMPAT_TO_UNDERLYING_HPP_INCLUDED

View File

@@ -0,0 +1,50 @@
#ifndef BOOST_COMPAT_TYPE_TRAITS_HPP_INCLUDED
#define BOOST_COMPAT_TYPE_TRAITS_HPP_INCLUDED
// Copyright 2024 Peter Dimov
// Copyright 2024-2025 Christian Mazakas
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <type_traits>
namespace boost {
namespace compat {
template<class T> using add_lvalue_reference_t = typename std::add_lvalue_reference<T>::type;
template<class T> using add_rvalue_reference_t = typename std::add_rvalue_reference<T>::type;
template<class T> using remove_const_t = typename std::remove_const<T>::type;
template<class T> using remove_cv_t = typename std::remove_cv<T>::type;
template<class T> using remove_reference_t = typename std::remove_reference<T>::type;
template<class T> using remove_cvref_t = remove_cv_t< remove_reference_t<T> >;
template<class T> using remove_pointer_t = typename std::remove_pointer<T>::type;
template<class T> using decay_t = typename std::decay<T>::type;
template<bool B, class T = void> using enable_if_t = typename std::enable_if<B, T>::type;
template<bool B, class T, class F> using conditional_t = typename std::conditional<B, T, F>::type;
namespace detail {
template<class...> struct make_void
{
using type = void;
};
} // namespace detail
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;
template<class T> struct type_identity
{
using type = T;
};
} // namespace compat
} // namespace boost
#endif // BOOST_COMPAT_TYPE_TRAITS_HPP_INCLUDED

View File

@@ -2,7 +2,8 @@
"key": "compat",
"name": "Compat",
"authors": [
"Peter Dimov"
"Peter Dimov",
"Christian Mazakas"
],
"maintainers": [
"Peter Dimov <pdimov -at- gmail.com>"

View File

@@ -8,6 +8,7 @@ if(HAVE_BOOST_TEST)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
boost_test_jamfile(FILE Jamfile LINK_LIBRARIES Boost::compat Boost::core Threads::Threads)
boost_test_jamfile(FILE Jamfile LINK_LIBRARIES Boost::compat Boost::core Boost::mp11 Threads::Threads)
endif()

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,10 +21,103 @@ 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 ;
run latch_test.cpp ;
run shared_lock_test.cpp ;
run shared_lock_test.cpp : : : <exception-handling>off : shared_lock_test_nx ;
run invoke_fn_test.cpp ;
run invoke_obj_test.cpp ;
run invoke_mfn_test.cpp ;
run invoke_md_test.cpp ;
run mem_fn_mfn_test.cpp ;
run mem_fn_md_test.cpp ;
run invoke_fn_noexcept_test.cpp ;
run invoke_obj_noexcept_test.cpp ;
run invoke_mfn_noexcept_test.cpp ;
run invoke_md_noexcept_test.cpp ;
compile invoke_fn_constexpr_test.cpp ;
compile invoke_obj_constexpr_test.cpp ;
compile invoke_mfn_constexpr_test.cpp
: <toolset>gcc-4.8:<build>no <toolset>gcc-4.9:<build>no ;
compile invoke_md_constexpr_test.cpp
: <toolset>gcc-4.8:<build>no <toolset>gcc-4.9:<build>no ;
run invoke_result_test.cpp ;
run is_invocable_test.cpp ;
run is_nothrow_invocable_test.cpp ;
run bind_front_fn_test.cpp ;
run bind_front_obj_test.cpp ;
run bind_front_mfn_test.cpp ;
run bind_front_md_test.cpp ;
compile bind_front_fn_constexpr_test.cpp ;
compile bind_front_obj_constexpr_test.cpp ;
compile bind_front_mfn_constexpr_test.cpp ;
compile bind_front_md_constexpr_test.cpp ;
run integer_sequence_test.cpp ;
run bind_back_fn_test.cpp ;
run bind_back_obj_test.cpp ;
run bind_back_mfn_test.cpp ;
run bind_back_md_test.cpp ;
compile bind_back_fn_constexpr_test.cpp ;
compile bind_back_obj_constexpr_test.cpp ;
compile bind_back_mfn_constexpr_test.cpp ;
compile bind_back_md_constexpr_test.cpp ;
run invoke_r_fn_test.cpp ;
run invoke_r_obj_test.cpp ;
run invoke_r_mfn_test.cpp ;
run invoke_r_md_test.cpp ;
run invoke_r_fn_noexcept_test.cpp ;
run invoke_r_obj_noexcept_test.cpp ;
run invoke_r_mfn_noexcept_test.cpp ;
run invoke_r_md_noexcept_test.cpp ;
compile invoke_r_fn_constexpr_test.cpp ;
compile invoke_r_obj_constexpr_test.cpp ;
compile invoke_r_mfn_constexpr_test.cpp
: <toolset>gcc-4.8:<build>no <toolset>gcc-4.9:<build>no ;
compile invoke_r_md_constexpr_test.cpp
: <toolset>gcc-4.8:<build>no <toolset>gcc-4.9:<build>no ;
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 ;
run move_only_function_test.cpp ;
run to_array_lvalue_test.cpp ;
run to_array_rvalue_test.cpp ;
run to_underlying_test.cpp ;
run nontype_test.cpp ;

View File

@@ -0,0 +1,60 @@
// Copyright 2024 Peter Dimov
// 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/bind_back.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_NO_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}
#else
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
#define BOOST_TEST_EQ(x, y) STATIC_ASSERT((x) == (y))
constexpr int f0()
{
return -1;
}
constexpr int f1( int x1 ) noexcept
{
return x1;
}
constexpr int f2( int x1, int x2 )
{
return 10*x1+x2;
}
constexpr int f3( int x1, int x2, int x3 ) noexcept
{
return 100*x1 + 10*x2 + x3;
}
int main()
{
BOOST_TEST_EQ( boost::compat::bind_back( f0 )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( f1 )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( f2 )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( f3 )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( f1, 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( f2, 1 )( 2 ), 21 );
BOOST_TEST_EQ( boost::compat::bind_back( f3, 1 )( 2, 3 ), 231 );
BOOST_TEST_EQ( boost::compat::bind_back( f2, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( f3, 1, 2 )( 3 ), 312 );
BOOST_TEST_EQ( boost::compat::bind_back( f3, 1, 2, 3 )(), 123 );
}
#endif

View File

@@ -0,0 +1,57 @@
// Copyright 2024 Peter Dimov
// 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/bind_back.hpp>
#include <boost/core/lightweight_test.hpp>
#include <memory>
int f0()
{
return -1;
}
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;
}
int main()
{
BOOST_TEST_EQ( boost::compat::bind_back( f0 )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( f1 )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( f2 )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( f3 )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( f1, 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( f2, 1 )( 2 ), 21 );
BOOST_TEST_EQ( boost::compat::bind_back( f3, 1 )( 2, 3 ), 231 );
BOOST_TEST_EQ( boost::compat::bind_back( f2, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( f3, 1, 2 )( 3 ), 312 );
BOOST_TEST_EQ( boost::compat::bind_back( f3, 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( g, std::unique_ptr<int>( new int(1) ) )( std::unique_ptr<int>( new int(2) ) ), 21 );
return boost::report_errors();
}

View File

@@ -0,0 +1,58 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/bind_back.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_NO_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}
#else
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
#define BOOST_TEST_EQ(x, y) STATIC_ASSERT((x) == (y))
struct X
{
int m = -1;
};
struct Y: public X
{
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, X() )(), -1 );
}
{
constexpr X x = {};
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, x )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, &x )(), -1 );
}
#if !BOOST_WORKAROUND(BOOST_MSVC, >= 1920 && BOOST_MSVC < 1950)
{
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, Y() )(), -1 );
}
{
constexpr Y y = {};
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, y )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, &y )(), -1 );
}
#endif
}
#endif

101
test/bind_back_md_test.cpp Normal file
View File

@@ -0,0 +1,101 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/bind_back.hpp>
#include <boost/core/lightweight_test.hpp>
#include <functional>
struct X
{
int m = -1;
};
struct Y: public virtual X
{
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, X() )(), -1 );
}
{
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, Y() )(), -1 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, x )(), -1 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, &x )(), -1 );
boost::compat::bind_back( &X::m, &x )() = +1;
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, &x )(), +1 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, std::ref(x) )(), -1 );
boost::compat::bind_back( &X::m, std::ref(x) )() = +1;
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, std::ref(x) )(), +1 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, std::cref(x) )(), -1 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, y )(), -1 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, &y )(), -1 );
boost::compat::bind_back( &X::m, &y )() = +1;
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, &y )(), +1 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, std::ref(y) )(), -1 );
boost::compat::bind_back( &X::m, std::ref(y) )() = +1;
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, std::ref(y) )(), +1 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, std::cref(y) )(), -1 );
}
{
X const x = {};
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, x )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, &x )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, std::ref(x) )(), -1 );
}
{
Y const y = {};
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, y )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, &y )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::m, std::ref(y) )(), -1 );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,137 @@
// Copyright 2024 Peter Dimov
// 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/bind_back.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_NO_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}
#else
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
#define BOOST_TEST_EQ(x, y) STATIC_ASSERT((x) == (y))
struct X
{
constexpr int f0()
{
return -1;
}
constexpr int f1( int x1 ) noexcept
{
return x1;
}
constexpr int f2( int x1, int x2 ) const
{
return 10*x1+x2;
}
constexpr int f3( int x1, int x2, int x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
struct Y: public X
{
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::bind_back( &X::f0 )( X() ), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1 )( X(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( X(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( X(), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, X(), 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, X(), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, X(), 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, 1 )( X() ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( X() ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( X() ), 123 );
}
{
BOOST_TEST_EQ( boost::compat::bind_back( &X::f0 )( Y() ), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1 )( Y(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( Y(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( Y(), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, Y(), 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, Y(), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, Y(), 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, 1 )( Y() ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( Y() ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( Y() ), 123 );
}
{
constexpr X x = {};
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, x, 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( x ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( x ), 123 );
}
{
constexpr Y x = {};
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, x, 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( x ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( x ), 123 );
}
{
constexpr X x = {};
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( &x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, &x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, &x, 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( &x ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( &x ), 123 );
}
{
constexpr Y x = {};
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( &x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, &x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, &x, 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( &x ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( &x ), 123 );
}
}
#endif

308
test/bind_back_mfn_test.cpp Normal file
View File

@@ -0,0 +1,308 @@
// Copyright 2024 Peter Dimov
// 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/bind_back.hpp>
#include <boost/core/lightweight_test.hpp>
#include <functional>
#include <memory>
struct X
{
int f0()
{
return -1;
}
int f1( int x1 ) noexcept
{
return x1;
}
int f2( int x1, int x2 ) const
{
return 10*x1+x2;
}
int f3( int x1, int x2, int x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
struct Y: public virtual X
{
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::bind_back( &X::f0 )( X() ), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1 )( X(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( X(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( X(), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, X(), 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, X(), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, X(), 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, 1 )( X() ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( X() ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( X() ), 123 );
}
{
BOOST_TEST_EQ( boost::compat::bind_back( &X::f0 )( Y() ), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1 )( Y(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( Y(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( Y(), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, Y(), 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, Y(), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, Y(), 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, 1 )( Y() ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( Y() ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( Y() ), 123 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::bind_back( &X::f0 )( x ), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1 )( x, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, x, 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, x, 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, 1 )( x ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( x ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( x ), 123 );
}
{
Y x;
BOOST_TEST_EQ( boost::compat::bind_back( &X::f0 )( x ), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1 )( x, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, x, 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, x, 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, 1 )( x ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( x ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( x ), 123 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::bind_back( &X::f0 )( &x ), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1 )( &x, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( &x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, &x, 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, &x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, &x, 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, 1 )( &x ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( &x ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( &x ), 123 );
}
{
Y x;
BOOST_TEST_EQ( boost::compat::bind_back( &X::f0 )( &x ), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1 )( &x, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( &x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, &x, 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, &x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, &x, 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, 1 )( &x ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( &x ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( &x ), 123 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::bind_back( &X::f0 )( std::ref(x) ), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1 )( std::ref(x), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( std::ref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( std::ref(x), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, std::ref(x), 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, std::ref(x), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, std::ref(x), 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, 1 )( std::ref(x) ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( std::ref(x) ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( std::ref(x) ), 123 );
}
{
Y x;
BOOST_TEST_EQ( boost::compat::bind_back( &X::f0 )( std::ref(x) ), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1 )( std::ref(x), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( std::ref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( std::ref(x), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, std::ref(x), 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, std::ref(x), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, std::ref(x), 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f1, 1 )( std::ref(x) ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( std::ref(x) ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( std::ref(x) ), 123 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( std::cref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( std::cref(x), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, std::cref(x), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, std::cref(x), 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( std::cref(x) ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( std::cref(x) ), 123 );
}
{
Y x;
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( std::cref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( std::cref(x), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, std::cref(x), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, std::cref(x), 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( std::cref(x) ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( std::cref(x) ), 123 );
}
{
X const x = {};
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, x, 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( x ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( x ), 123 );
}
{
Y const x = {};
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, x, 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( x ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( x ), 123 );
}
{
X const x = {};
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( &x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, &x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, &x, 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( &x ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( &x ), 123 );
}
{
Y const x = {};
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( &x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, &x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, &x, 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( &x ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( &x ), 123 );
}
{
X const x = {};
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( std::ref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( std::ref(x), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, std::ref(x), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, std::ref(x), 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( std::ref(x) ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( std::ref(x) ), 123 );
}
{
Y const x = {};
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2 )( std::ref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3 )( std::ref(x), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, std::ref(x), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, std::ref(x), 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f2, 1, 2 )( std::ref(x) ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( std::ref(x) ), 123 );
}
{
std::unique_ptr<X> px( new X );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( std::move(px) ), 123 );
}
{
std::unique_ptr<Y> px( new Y );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, 1, 2, 3 )( std::move(px) ), 123 );
}
{
std::unique_ptr<X> px( new X );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, std::move(px), 1, 2, 3 )(), 123 );
}
{
std::unique_ptr<Y> px( new Y );
BOOST_TEST_EQ( boost::compat::bind_back( &X::f3, std::move(px), 1, 2, 3 )(), 123 );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,96 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/bind_back.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_NO_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}
#else
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
#define BOOST_TEST_EQ(x, y) STATIC_ASSERT((x) == (y))
struct F1
{
constexpr int operator()()
{
return -1;
}
constexpr int operator()( int x1 ) noexcept
{
return x1;
}
constexpr int operator()( int x1, int x2 ) const
{
return 10*x1+x2;
}
constexpr int operator()( int x1, int x2, int x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
struct F2
{
constexpr int operator()( int x1, int x2 ) &
{
return 100*x1 + 10*x2 + 1;
}
constexpr int operator()( int x1, int x2 ) const &
{
return 100*x1 + 10*x2 + 2;
}
constexpr int operator()( int x1, int x2 ) &&
{
return 100*x1 + 10*x2 + 3;
}
constexpr int operator()( int x1, int x2 ) const &&
{
return 100*x1 + 10*x2 + 4;
}
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::bind_back( F1() )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( F1() )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( F1() )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( F1() )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( F1(), 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( F1(), 1 )( 2 ), 21 );
BOOST_TEST_EQ( boost::compat::bind_back( F1(), 1 )( 2, 3 ), 231 );
BOOST_TEST_EQ( boost::compat::bind_back( F1(), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( F1(), 1, 2 )( 3 ), 312 );
BOOST_TEST_EQ( boost::compat::bind_back( F1(), 1, 2, 3 )(), 123 );
}
{
BOOST_TEST_EQ( boost::compat::bind_back( F2(), 9 )( 8 ), 893 );
}
{
constexpr auto fn = boost::compat::bind_back( F2(), 9 );
BOOST_TEST_EQ( fn( 8 ), 892 );
}
{
constexpr auto fn = boost::compat::bind_back( F2(), 9 );
BOOST_TEST_EQ( std::move( fn )( 8 ), 894 );
}
}
#endif

101
test/bind_back_obj_test.cpp Normal file
View File

@@ -0,0 +1,101 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/bind_back.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.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;
}
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::bind_back( F1() )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_back( F1() )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( F1() )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( F1() )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_back( F1(), 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_back( F1(), 1 )( 2 ), 21 );
BOOST_TEST_EQ( boost::compat::bind_back( F1(), 1 )( 2, 3 ), 231 );
BOOST_TEST_EQ( boost::compat::bind_back( F1(), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_back( F1(), 1, 2 )( 3 ), 312 );
BOOST_TEST_EQ( boost::compat::bind_back( F1(), 1, 2, 3 )(), 123 );
}
{
BOOST_TEST_EQ( boost::compat::bind_back( F2(), 9 )( 8 ), 893 );
}
{
auto fn = boost::compat::bind_back( F2(), 9 );
BOOST_TEST_EQ( fn( 8 ), 891 );
}
{
auto const fn = boost::compat::bind_back( F2(), 9 );
BOOST_TEST_EQ( fn( 8 ), 892 );
}
{
auto fn = boost::compat::bind_back( F2(), 9 );
BOOST_TEST_EQ( std::move( fn )( 8 ), 893 );
}
#if !BOOST_WORKAROUND(BOOST_GCC, < 40900)
{
auto const fn = boost::compat::bind_back( F2(), 9 );
BOOST_TEST_EQ( std::move( fn )( 8 ), 894 );
}
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,60 @@
// Copyright 2024 Peter Dimov
// 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/bind_front.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_NO_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}
#else
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
#define BOOST_TEST_EQ(x, y) STATIC_ASSERT((x) == (y))
constexpr int f0()
{
return -1;
}
constexpr int f1( int x1 ) noexcept
{
return x1;
}
constexpr int f2( int x1, int x2 )
{
return 10*x1+x2;
}
constexpr int f3( int x1, int x2, int x3 ) noexcept
{
return 100*x1 + 10*x2 + x3;
}
int main()
{
BOOST_TEST_EQ( boost::compat::bind_front( f0 )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( f1 )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( f2 )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( f3 )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( f1, 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( f2, 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( f3, 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( f2, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( f3, 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( f3, 1, 2, 3 )(), 123 );
}
#endif

View File

@@ -0,0 +1,57 @@
// Copyright 2024 Peter Dimov
// 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/bind_front.hpp>
#include <boost/core/lightweight_test.hpp>
#include <memory>
int f0()
{
return -1;
}
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;
}
int main()
{
BOOST_TEST_EQ( boost::compat::bind_front( f0 )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( f1 )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( f2 )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( f3 )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( f1, 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( f2, 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( f3, 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( f2, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( f3, 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( f3, 1, 2, 3 )(), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( g, std::unique_ptr<int>( new int(1) ) )( std::unique_ptr<int>( new int(2) ) ), 12 );
return boost::report_errors();
}

View File

@@ -0,0 +1,58 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/bind_front.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_NO_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}
#else
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
#define BOOST_TEST_EQ(x, y) STATIC_ASSERT((x) == (y))
struct X
{
int m = -1;
};
struct Y: public X
{
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, X() )(), -1 );
}
{
constexpr X x = {};
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, x )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, &x )(), -1 );
}
#if !BOOST_WORKAROUND(BOOST_MSVC, >= 1920 && BOOST_MSVC < 1950)
{
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, Y() )(), -1 );
}
{
constexpr Y y = {};
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, y )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, &y )(), -1 );
}
#endif
}
#endif

101
test/bind_front_md_test.cpp Normal file
View File

@@ -0,0 +1,101 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/bind_front.hpp>
#include <boost/core/lightweight_test.hpp>
#include <functional>
struct X
{
int m = -1;
};
struct Y: public virtual X
{
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, X() )(), -1 );
}
{
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, Y() )(), -1 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, x )(), -1 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, &x )(), -1 );
boost::compat::bind_front( &X::m, &x )() = +1;
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, &x )(), +1 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, std::ref(x) )(), -1 );
boost::compat::bind_front( &X::m, std::ref(x) )() = +1;
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, std::ref(x) )(), +1 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, std::cref(x) )(), -1 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, y )(), -1 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, &y )(), -1 );
boost::compat::bind_front( &X::m, &y )() = +1;
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, &y )(), +1 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, std::ref(y) )(), -1 );
boost::compat::bind_front( &X::m, std::ref(y) )() = +1;
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, std::ref(y) )(), +1 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, std::cref(y) )(), -1 );
}
{
X const x = {};
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, x )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, &x )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, std::ref(x) )(), -1 );
}
{
Y const y = {};
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, y )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, &y )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::m, std::ref(y) )(), -1 );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,167 @@
// Copyright 2024 Peter Dimov
// 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/bind_front.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_NO_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}
#else
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
#define BOOST_TEST_EQ(x, y) STATIC_ASSERT((x) == (y))
struct X
{
constexpr int f0()
{
return -1;
}
constexpr int f1( int x1 ) noexcept
{
return x1;
}
constexpr int f2( int x1, int x2 ) const
{
return 10*x1+x2;
}
constexpr int f3( int x1, int x2, int x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
struct Y: public X
{
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0 )( X() ), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1 )( X(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( X(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( X(), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0, X() )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, X() )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, X() )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, X() )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, X(), 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, X(), 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, X(), 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, X(), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, X(), 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, X(), 1, 2, 3 )(), 123 );
}
{
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0, Y() )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, Y() )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, Y() )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, Y() )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0, Y() )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, Y() )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, Y() )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, Y() )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, Y(), 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, Y(), 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, Y(), 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, Y(), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, Y(), 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, Y(), 1, 2, 3 )(), 123 );
}
{
constexpr X x = {};
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, x )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, x, 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x, 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x, 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x, 1, 2, 3 )(), 123 );
}
{
constexpr X x = {};
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( &x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, &x )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, &x, 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x, 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, &x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x, 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x, 1, 2, 3 )(), 123 );
}
{
constexpr Y x = {};
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, x )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, x, 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x, 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x, 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x, 1, 2, 3 )(), 123 );
}
{
constexpr Y x = {};
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( &x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, &x )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, &x, 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x, 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, &x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x, 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x, 1, 2, 3 )(), 123 );
}
}
#endif

View File

@@ -0,0 +1,378 @@
// Copyright 2024 Peter Dimov
// 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/bind_front.hpp>
#include <boost/core/lightweight_test.hpp>
#include <functional>
#include <memory>
struct X
{
int f0()
{
return -1;
}
int f1( int x1 ) noexcept
{
return x1;
}
int f2( int x1, int x2 ) const
{
return 10*x1+x2;
}
int f3( int x1, int x2, int x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
struct Y: public virtual X
{
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0 )( X() ), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1 )( X(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( X(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( X(), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0, X() )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, X() )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, X() )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, X() )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, X(), 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, X(), 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, X(), 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, X(), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, X(), 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, X(), 1, 2, 3 )(), 123 );
}
{
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0, Y() )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, Y() )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, Y() )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, Y() )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0, Y() )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, Y() )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, Y() )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, Y() )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, Y(), 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, Y(), 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, Y(), 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, Y(), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, Y(), 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, Y(), 1, 2, 3 )(), 123 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0 )( x ), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1 )( x, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0, x )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, x )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, x )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, x, 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, x, 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x, 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x, 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x, 1, 2, 3 )(), 123 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0 )( &x ), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1 )( &x, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( &x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0, &x )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, &x )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, &x )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, &x, 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, &x, 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x, 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, &x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x, 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x, 1, 2, 3 )(), 123 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0 )( std::ref(x) ), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1 )( std::ref(x), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( std::ref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( std::ref(x), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0, std::ref(x) )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, std::ref(x) )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, std::ref(x) )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::ref(x) )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, std::ref(x), 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, std::ref(x), 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::ref(x), 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, std::ref(x), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::ref(x), 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::ref(x), 1, 2, 3 )(), 123 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( std::cref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( std::cref(x), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, std::cref(x) )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::cref(x) )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, std::cref(x), 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::cref(x), 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, std::cref(x), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::cref(x), 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::cref(x), 1, 2, 3 )(), 123 );
}
{
Y x;
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0 )( x ), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1 )( x, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0, x )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, x )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, x )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, x, 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, x, 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x, 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x, 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x, 1, 2, 3 )(), 123 );
}
{
Y x;
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0 )( &x ), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1 )( &x, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( &x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0, &x )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, &x )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, &x )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, &x, 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, &x, 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x, 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, &x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x, 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x, 1, 2, 3 )(), 123 );
}
{
Y x;
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0 )( std::ref(x) ), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1 )( std::ref(x), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( std::ref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( std::ref(x), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f0, std::ref(x) )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, std::ref(x) )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, std::ref(x) )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::ref(x) )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f1, std::ref(x), 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, std::ref(x), 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::ref(x), 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, std::ref(x), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::ref(x), 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::ref(x), 1, 2, 3 )(), 123 );
}
{
Y x;
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( std::cref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( std::cref(x), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, std::cref(x) )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::cref(x) )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, std::cref(x), 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::cref(x), 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, std::cref(x), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::cref(x), 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::cref(x), 1, 2, 3 )(), 123 );
}
{
X const x = {};
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, x )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, x, 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x, 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x, 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x, 1, 2, 3 )(), 123 );
}
{
X const x = {};
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( &x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, &x )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, &x, 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x, 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, &x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x, 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x, 1, 2, 3 )(), 123 );
}
{
X const x = {};
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( std::ref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( std::ref(x), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, std::ref(x) )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::ref(x) )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, std::ref(x), 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::ref(x), 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, std::ref(x), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::ref(x), 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::ref(x), 1, 2, 3 )(), 123 );
}
{
Y const x = {};
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, x )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, x, 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x, 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x, 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, x, 1, 2, 3 )(), 123 );
}
{
Y const x = {};
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( &x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, &x )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, &x, 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x, 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, &x, 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x, 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, &x, 1, 2, 3 )(), 123 );
}
{
Y const x = {};
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2 )( std::ref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3 )( std::ref(x), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, std::ref(x) )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::ref(x) )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, std::ref(x), 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::ref(x), 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f2, std::ref(x), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::ref(x), 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::ref(x), 1, 2, 3 )(), 123 );
}
{
std::unique_ptr<X> px( new X );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::move(px), 1 )( 2, 3 ), 123 );
}
{
std::unique_ptr<Y> px( new Y );
BOOST_TEST_EQ( boost::compat::bind_front( &X::f3, std::move(px), 1 )( 2, 3 ), 123 );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,96 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/bind_front.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if defined(BOOST_NO_CXX14_CONSTEXPR)
BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_NO_CXX14_CONSTEXPR is defined" )
int main() {}
#else
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
#define BOOST_TEST_EQ(x, y) STATIC_ASSERT((x) == (y))
struct F1
{
constexpr int operator()()
{
return -1;
}
constexpr int operator()( int x1 ) noexcept
{
return x1;
}
constexpr int operator()( int x1, int x2 ) const
{
return 10*x1+x2;
}
constexpr int operator()( int x1, int x2, int x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
struct F2
{
constexpr int operator()( int x1, int x2 ) &
{
return 100*x1 + 10*x2 + 1;
}
constexpr int operator()( int x1, int x2 ) const &
{
return 100*x1 + 10*x2 + 2;
}
constexpr int operator()( int x1, int x2 ) &&
{
return 100*x1 + 10*x2 + 3;
}
constexpr int operator()( int x1, int x2 ) const &&
{
return 100*x1 + 10*x2 + 4;
}
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::bind_front( F1() )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( F1() )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( F1() )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( F1() )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( F1(), 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( F1(), 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( F1(), 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( F1(), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( F1(), 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( F1(), 1, 2, 3 )(), 123 );
}
{
BOOST_TEST_EQ( boost::compat::bind_front( F2(), 9 )( 8 ), 983 );
}
{
constexpr auto fn = boost::compat::bind_front( F2(), 9 );
BOOST_TEST_EQ( fn( 8 ), 982 );
}
{
constexpr auto fn = boost::compat::bind_front( F2(), 9 );
BOOST_TEST_EQ( std::move( fn )( 8 ), 984 );
}
}
#endif

View File

@@ -0,0 +1,101 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/bind_front.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.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;
}
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::bind_front( F1() )(), -1 );
BOOST_TEST_EQ( boost::compat::bind_front( F1() )( 1 ), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( F1() )( 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( F1() )( 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( F1(), 1 )(), 1 );
BOOST_TEST_EQ( boost::compat::bind_front( F1(), 1 )( 2 ), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( F1(), 1 )( 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( F1(), 1, 2 )(), 12 );
BOOST_TEST_EQ( boost::compat::bind_front( F1(), 1, 2 )( 3 ), 123 );
BOOST_TEST_EQ( boost::compat::bind_front( F1(), 1, 2, 3 )(), 123 );
}
{
BOOST_TEST_EQ( boost::compat::bind_front( F2(), 9 )( 8 ), 983 );
}
{
auto fn = boost::compat::bind_front( F2(), 9 );
BOOST_TEST_EQ( fn( 8 ), 981 );
}
{
auto const fn = boost::compat::bind_front( F2(), 9 );
BOOST_TEST_EQ( fn( 8 ), 982 );
}
{
auto fn = boost::compat::bind_front( F2(), 9 );
BOOST_TEST_EQ( std::move( fn )( 8 ), 983 );
}
#if !BOOST_WORKAROUND(BOOST_GCC, < 40900)
{
auto const fn = boost::compat::bind_front( F2(), 9 );
BOOST_TEST_EQ( std::move( fn )( 8 ), 984 );
}
#endif
return boost::report_errors();
}

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,184 @@
// 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
{
int x = 1;
compat::function_ref<int(int)> fv1(f1);
BOOST_TEST_EQ(fv1(x), 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,186 @@
// 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/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <memory>
#include <type_traits>
#if defined(__cpp_nontype_template_parameter_auto) && __cpp_nontype_template_parameter_auto >= 201606L
#define NONTYPE(fn) compat::nontype<fn>
#define NONTYPE_T(fn) compat::nontype_t<fn>
#else
#define NONTYPE(fn) compat::detail::nttp_holder<decltype(fn), fn>{}
#define NONTYPE_T(fn) compat::detail::nttp_holder<decltype(fn), fn>
#endif
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() {
{
#if defined(__cpp_noexcept_function_types)
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(F1&) noexcept>, NONTYPE_T(&F1::m1)>));
#endif
BOOST_TEST_TRAIT_TRUE(
(std::is_constructible<compat::function_ref<int(F1&, int) noexcept>, NONTYPE_T(&F1::m2)>));
#if defined(__cpp_noexcept_function_types)
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(F1&, int, int) noexcept>, NONTYPE_T(&F1::m3)>));
#endif
BOOST_TEST_TRAIT_TRUE(
(std::is_constructible<compat::function_ref<int(F1&, int, int, int) noexcept>, NONTYPE_T(&F1::m4)>));
}
{
F1 f1;
compat::function_ref<int(F1&, int) noexcept> fn2(NONTYPE(&F1::m2));
BOOST_TEST_EQ(fn2(f1, 2), 12);
compat::function_ref<int(F1&, int, int, int) noexcept> fn4(NONTYPE(&F1::m4));
BOOST_TEST_EQ(fn4(f1, 2, 3, 4), 1234);
}
{
#if defined(__cpp_noexcept_function_types)
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(F1&) const noexcept>, NONTYPE_T(&F1::m1)>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(F1&, int, int) const noexcept>, NONTYPE_T(&F1::m3)>));
#endif
F1 f1;
compat::function_ref<int(F1&, int) const noexcept> fn2(NONTYPE(&F1::m2));
BOOST_TEST_EQ(fn2(f1, 2), 12);
compat::function_ref<int(F1&, int, int, int) const noexcept> fn4(NONTYPE(&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>, NONTYPE_T(&F1::m1)>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(F1 const&, int) noexcept>, NONTYPE_T(&F1::m2)>));
#if defined(__cpp_noexcept_function_types)
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(F1 const&, int, int) noexcept>, NONTYPE_T(&F1::m3)>));
#endif
F1 f1;
compat::function_ref<int(F1 const&, int, int, int) noexcept> fn4(NONTYPE(&F1::m4));
BOOST_TEST_EQ(fn4(f1, 2, 3, 4), 1234);
}
{
#if defined(__cpp_noexcept_function_types)
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int() noexcept>, NONTYPE_T(&F1::m1), F1&>));
#endif
BOOST_TEST_TRAIT_TRUE(
(std::is_constructible<compat::function_ref<int(int) noexcept>, NONTYPE_T(&F1::m2), F1&>));
#if defined(__cpp_noexcept_function_types)
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(int, int) noexcept>, NONTYPE_T(&F1::m3), F1&>));
#endif
BOOST_TEST_TRAIT_TRUE(
(std::is_constructible<compat::function_ref<int(int, int, int) noexcept>, NONTYPE_T(&F1::m4), F1&>));
F1 f1;
compat::function_ref<int(int) noexcept> fn2(NONTYPE(&F1::m2), f1);
BOOST_TEST_EQ(fn2(2), 12);
compat::function_ref<int(int, int, int) noexcept> fn4(NONTYPE(&F1::m4), f1);
BOOST_TEST_EQ(fn4(2, 3, 4), 1234);
}
{
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int() const noexcept>, NONTYPE_T(&F1::m1), F1 const&>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(int) const noexcept>, NONTYPE_T(&F1::m2), F1 const&>));
#if defined(__cpp_noexcept_function_types)
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<int(int, int) const noexcept>,
NONTYPE_T(&F1::m3), F1 const&>));
#endif
F1 f1;
compat::function_ref<int(int, int, int) const noexcept> fn4(NONTYPE(&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(NONTYPE(&F1::m4), f1_2);
BOOST_TEST_EQ(fn4_2(2, 3, 4), 1234);
}
{
#if defined(__cpp_noexcept_function_types)
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int() noexcept>, NONTYPE_T(&F1::m1), F1*>));
#endif
BOOST_TEST_TRAIT_TRUE(
(std::is_constructible<compat::function_ref<int(int) noexcept>, NONTYPE_T(&F1::m2), F1*>));
#if defined(__cpp_noexcept_function_types)
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(int, int) noexcept>, NONTYPE_T(&F1::m3), F1*>));
#endif
BOOST_TEST_TRAIT_TRUE(
(std::is_constructible<compat::function_ref<int(int, int, int) noexcept>, NONTYPE_T(&F1::m4), F1*>));
F1 f1;
compat::function_ref<int(int) noexcept> fn2(NONTYPE(&F1::m2), &f1);
BOOST_TEST_EQ(fn2(2), 12);
compat::function_ref<int(int, int, int) noexcept> fn4(NONTYPE(&F1::m4), &f1);
BOOST_TEST_EQ(fn4(2, 3, 4), 1234);
}
{
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int() const noexcept>, NONTYPE_T(&F1::m1), F1 const*>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(int) const noexcept>, NONTYPE_T(&F1::m2), F1 const*>));
#if defined(__cpp_noexcept_function_types)
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<int(int, int) const noexcept>,
NONTYPE_T(&F1::m3), F1 const*>));
#endif
F1 const f1;
compat::function_ref<int(int, int, int) const noexcept> fn4(NONTYPE(&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(NONTYPE(&F1::m4), &f1_2);
BOOST_TEST_EQ(fn4_2(2, 3, 4), 1234);
}
return boost::report_errors();
}

View File

@@ -0,0 +1,179 @@
// 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/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <memory>
#include <type_traits>
#if defined(__cpp_nontype_template_parameter_auto) && __cpp_nontype_template_parameter_auto >= 201606L
#define NONTYPE(fn) compat::nontype<fn>
#define NONTYPE_T(fn) compat::nontype_t<fn>
#else
#define NONTYPE(fn) compat::detail::nttp_holder<decltype(fn), fn>{}
#define NONTYPE_T(fn) compat::detail::nttp_holder<decltype(fn), fn>
#endif
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(NONTYPE(&F1::m1));
BOOST_TEST_EQ(fn1(f1), 0);
int x = 2;
compat::function_ref<int(F1&, int)> fn2(NONTYPE(&F1::m2));
BOOST_TEST_EQ(fn2(f1, x), 12);
compat::function_ref<int(F1&, int, int)> fn3(NONTYPE(&F1::m3));
BOOST_TEST_EQ(fn3(f1, 2, 3), 123);
compat::function_ref<int(F1&, int, int, int)> fn4(NONTYPE(&F1::m4));
BOOST_TEST_EQ(fn4(f1, 2, 3, 4), 1234);
compat::function_ref<int(F1&)> a1(NONTYPE(&F1::q_));
BOOST_TEST_EQ(a1(f1), 1337);
}
{
F1 f1;
compat::function_ref<int(F1&) const> fn1(NONTYPE(&F1::m1));
BOOST_TEST_EQ(fn1(f1), 0);
compat::function_ref<int(F1&, int) const> fn2(NONTYPE(&F1::m2));
BOOST_TEST_EQ(fn2(f1, 2), 12);
compat::function_ref<int(F1&, int, int) const> fn3(NONTYPE(&F1::m3));
BOOST_TEST_EQ(fn3(f1, 2, 3), 123);
compat::function_ref<int(F1&, int, int, int) const> fn4(NONTYPE(&F1::m4));
BOOST_TEST_EQ(fn4(f1, 2, 3, 4), 1234);
}
{
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<int(F1 const&)>, NONTYPE_T(&F1::m1)>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(F1 const&, int)>, NONTYPE_T(&F1::m2)>));
F1 f1;
compat::function_ref<int(F1 const&, int, int) const> fn3(NONTYPE(&F1::m3));
BOOST_TEST_EQ(fn3(f1, 2, 3), 123);
compat::function_ref<int(F1 const&, int, int, int) const> fn4(NONTYPE(&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(NONTYPE(&F1::m3));
BOOST_TEST_EQ(fn3(f2, 2, 3), 123);
compat::function_ref<int(F1 const&, int, int, int) const> fn24(NONTYPE(&F1::m4));
BOOST_TEST_EQ(fn4(f2, 2, 3, 4), 1234);
}
{
BOOST_TEST_TRAIT_TRUE((std::is_constructible<compat::function_ref<int(int)>, NONTYPE_T(&F1::m2), F1&>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(int)>, NONTYPE_T(&F1::m2), F1 const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<int(int)>, NONTYPE_T(&F1::m2), F1&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<int(int)>, NONTYPE_T(&F1::m2), F1>));
BOOST_TEST_TRAIT_TRUE(
(std::is_constructible<compat::function_ref<int(int, int) const>, NONTYPE_T(&F1::m3), F1&>));
BOOST_TEST_TRAIT_TRUE(
(std::is_constructible<compat::function_ref<int(int, int) const>, NONTYPE_T(&F1::m3), F1 const&>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(int, int) const>, NONTYPE_T(&F1::m3), F1&&>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(int, int) const>, NONTYPE_T(&F1::m3), F1>));
}
{
F1 f1;
compat::function_ref<int()> fn1(NONTYPE(&F1::m1), f1);
BOOST_TEST_EQ(fn1(), 0);
compat::function_ref<int(int)> fn2(NONTYPE(&F1::m2), f1);
BOOST_TEST_EQ(fn2(2), 12);
compat::function_ref<int(int, int)> fn3(NONTYPE(&F1::m3), f1);
BOOST_TEST_EQ(fn3(2, 3), 123);
compat::function_ref<int(int, int, int)> fn4(NONTYPE(&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>, NONTYPE_T(&F1::m1), F1&>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(int) const>, NONTYPE_T(&F1::m2), F1&>));
compat::function_ref<int(int, int) const> fn3(NONTYPE(&F1::m3), f1);
BOOST_TEST_EQ(fn3(2, 3), 123);
compat::function_ref<int(int, int, int) const> fn4(NONTYPE(&F1::m4), f1);
BOOST_TEST_EQ(fn4(2, 3, 4), 1234);
}
{
F1 f1;
compat::function_ref<int()> fn1(NONTYPE(&F1::m1), &f1);
BOOST_TEST_EQ(fn1(), 0);
compat::function_ref<int(int)> fn2(NONTYPE(&F1::m2), &f1);
BOOST_TEST_EQ(fn2(2), 12);
compat::function_ref<int(int, int)> fn3(NONTYPE(&F1::m3), &f1);
BOOST_TEST_EQ(fn3(2, 3), 123);
compat::function_ref<int(int, int, int)> fn4(NONTYPE(&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>, NONTYPE_T(&F1::m1), F1 const*>));
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int(int) const>, NONTYPE_T(&F1::m2), F1 const*>));
compat::function_ref<int(int, int) const> fn3(NONTYPE(&F1::m3), &f1);
BOOST_TEST_EQ(fn3(2, 3), 123);
compat::function_ref<int(int, int, int) const> fn4(NONTYPE(&F1::m4), &f1);
BOOST_TEST_EQ(fn4(2, 3, 4), 1234);
}
return boost::report_errors();
}

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);
int x = 1;
BOOST_TEST_EQ(fv2(x), 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

@@ -0,0 +1,55 @@
// Copyright 2015 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/integer_sequence.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <type_traits>
#include <cstddef>
int main()
{
using boost::compat::integer_sequence;
using boost::compat::make_integer_sequence;
using boost::compat::index_sequence;
using boost::compat::make_index_sequence;
using boost::compat::index_sequence_for;
BOOST_TEST_TRAIT_SAME(make_integer_sequence<int, 0>, integer_sequence<int>);
BOOST_TEST_TRAIT_SAME(make_integer_sequence<int, 1>, integer_sequence<int, 0>);
BOOST_TEST_TRAIT_SAME(make_integer_sequence<int, 2>, integer_sequence<int, 0, 1>);
BOOST_TEST_TRAIT_SAME(make_integer_sequence<int, 3>, integer_sequence<int, 0, 1, 2>);
BOOST_TEST_TRAIT_SAME(make_integer_sequence<int, 4>, integer_sequence<int, 0, 1, 2, 3>);
BOOST_TEST_TRAIT_SAME(make_integer_sequence<char, 0>, integer_sequence<char>);
BOOST_TEST_TRAIT_SAME(make_integer_sequence<char, 1>, integer_sequence<char, 0>);
BOOST_TEST_TRAIT_SAME(make_integer_sequence<char, 2>, integer_sequence<char, 0, 1>);
BOOST_TEST_TRAIT_SAME(make_integer_sequence<char, 3>, integer_sequence<char, 0, 1, 2>);
BOOST_TEST_TRAIT_SAME(make_integer_sequence<char, 4>, integer_sequence<char, 0, 1, 2, 3>);
BOOST_TEST_TRAIT_SAME(make_integer_sequence<std::size_t, 0>, integer_sequence<std::size_t>);
BOOST_TEST_TRAIT_SAME(make_integer_sequence<std::size_t, 1>, integer_sequence<std::size_t, 0>);
BOOST_TEST_TRAIT_SAME(make_integer_sequence<std::size_t, 2>, integer_sequence<std::size_t, 0, 1>);
BOOST_TEST_TRAIT_SAME(make_integer_sequence<std::size_t, 3>, integer_sequence<std::size_t, 0, 1, 2>);
BOOST_TEST_TRAIT_SAME(make_integer_sequence<std::size_t, 4>, integer_sequence<std::size_t, 0, 1, 2, 3>);
BOOST_TEST_TRAIT_SAME(make_index_sequence<0>, integer_sequence<std::size_t>);
BOOST_TEST_TRAIT_SAME(make_index_sequence<1>, integer_sequence<std::size_t, 0>);
BOOST_TEST_TRAIT_SAME(make_index_sequence<2>, integer_sequence<std::size_t, 0, 1>);
BOOST_TEST_TRAIT_SAME(make_index_sequence<3>, integer_sequence<std::size_t, 0, 1, 2>);
BOOST_TEST_TRAIT_SAME(make_index_sequence<4>, integer_sequence<std::size_t, 0, 1, 2, 3>);
BOOST_TEST_TRAIT_SAME(make_index_sequence<0>, index_sequence<>);
BOOST_TEST_TRAIT_SAME(make_index_sequence<1>, index_sequence<0>);
BOOST_TEST_TRAIT_SAME(make_index_sequence<2>, index_sequence<0, 1>);
BOOST_TEST_TRAIT_SAME(make_index_sequence<3>, index_sequence<0, 1, 2>);
BOOST_TEST_TRAIT_SAME(make_index_sequence<4>, index_sequence<0, 1, 2, 3>);
BOOST_TEST_TRAIT_SAME(index_sequence_for<>, index_sequence<>);
BOOST_TEST_TRAIT_SAME(index_sequence_for<void>, index_sequence<0>);
BOOST_TEST_TRAIT_SAME(index_sequence_for<void, void>, index_sequence<0, 1>);
BOOST_TEST_TRAIT_SAME(index_sequence_for<void, void, void>, index_sequence<0, 1, 2>);
BOOST_TEST_TRAIT_SAME(index_sequence_for<void, void, void, void>, index_sequence<0, 1, 2, 3>);
return boost::report_errors();
}

View File

@@ -0,0 +1,40 @@
// Copyright 2024 Peter Dimov
// 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/invoke.hpp>
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
#define BOOST_TEST_EQ(x, y) STATIC_ASSERT((x) == (y))
constexpr int f0()
{
return -1;
}
constexpr int f1( int x1 ) noexcept
{
return x1;
}
constexpr int f2( int x1, int x2 )
{
return 10*x1+x2;
}
constexpr int f3( int x1, int x2, int x3 ) noexcept
{
return 100*x1 + 10*x2 + x3;
}
int main()
{
BOOST_TEST_EQ( boost::compat::invoke( f0 ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( f1, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( f2, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( f3, 1, 2, 3 ), 123 );
}

View File

@@ -0,0 +1,47 @@
// Copyright 2024 Peter Dimov
// 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/invoke.hpp>
#include <boost/core/lightweight_test.hpp>
int f0()
{
return -1;
}
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 main()
{
BOOST_TEST_EQ( noexcept( boost::compat::invoke( f0 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( f1, 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( f2, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( f3, 1, 2, 3 ) ), true );
return boost::report_errors();
}
#endif

40
test/invoke_fn_test.cpp Normal file
View File

@@ -0,0 +1,40 @@
// Copyright 2024 Peter Dimov
// 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/invoke.hpp>
#include <boost/core/lightweight_test.hpp>
int f0()
{
return -1;
}
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 main()
{
BOOST_TEST_EQ( boost::compat::invoke( f0 ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( f1, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( f2, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( f3, 1, 2, 3 ), 123 );
return boost::report_errors();
}

View File

@@ -0,0 +1,42 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/invoke.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
#define BOOST_TEST_EQ(x, y) STATIC_ASSERT((x) == (y))
struct X
{
int m = -1;
};
struct Y: public X
{
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::invoke( &X::m, X() ), -1 );
constexpr X x = {};
BOOST_TEST_EQ( boost::compat::invoke( &X::m, x ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::m, &x ), -1 );
}
#if !BOOST_WORKAROUND(BOOST_MSVC, >= 1920 && BOOST_MSVC < 1950)
{
BOOST_TEST_EQ( boost::compat::invoke( &X::m, Y() ), -1 );
constexpr Y y = {};
BOOST_TEST_EQ( boost::compat::invoke( &X::m, y ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::m, &y ), -1 );
}
#endif
}

View File

@@ -0,0 +1,60 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/invoke.hpp>
#include <boost/core/lightweight_test.hpp>
#include <functional>
struct X
{
int m = -1;
};
struct Y: public virtual X
{
};
int main()
{
{
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::m, X() ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::m, Y() ) ), true );
}
{
X x;
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::m, x ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::m, &x ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::m, std::ref(x) ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::m, std::cref(x) ) ), true );
}
{
Y y;
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::m, y ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::m, &y ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::m, std::ref(y) ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::m, std::cref(y) ) ), true );
}
{
X const x = {};
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::m, x ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::m, &x ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::m, std::ref(x) ) ), true );
}
{
Y const y = {};
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::m, y ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::m, &y ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::m, std::ref(y) ) ), true );
}
return boost::report_errors();
}

105
test/invoke_md_test.cpp Normal file
View File

@@ -0,0 +1,105 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/invoke.hpp>
#include <boost/core/lightweight_test.hpp>
#include <functional>
struct X
{
int m = -1;
};
struct Y: public virtual X
{
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::invoke( &X::m, X() ), -1 );
}
{
BOOST_TEST_EQ( boost::compat::invoke( &X::m, Y() ), -1 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::invoke( &X::m, x ), -1 );
boost::compat::invoke( &X::m, x ) = +1;
BOOST_TEST_EQ( boost::compat::invoke( &X::m, x ), +1 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::invoke( &X::m, &x ), -1 );
boost::compat::invoke( &X::m, &x ) = +1;
BOOST_TEST_EQ( boost::compat::invoke( &X::m, &x ), +1 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::invoke( &X::m, std::ref(x) ), -1 );
boost::compat::invoke( &X::m, std::ref(x) ) = +1;
BOOST_TEST_EQ( boost::compat::invoke( &X::m, std::ref(x) ), +1 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::invoke( &X::m, std::cref(x) ), -1 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::invoke( &X::m, y ), -1 );
boost::compat::invoke( &X::m, y ) = +1;
BOOST_TEST_EQ( boost::compat::invoke( &X::m, y ), +1 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::invoke( &X::m, &y ), -1 );
boost::compat::invoke( &X::m, &y ) = +1;
BOOST_TEST_EQ( boost::compat::invoke( &X::m, &y ), +1 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::invoke( &X::m, std::ref(y) ), -1 );
boost::compat::invoke( &X::m, std::ref(y) ) = +1;
BOOST_TEST_EQ( boost::compat::invoke( &X::m, std::ref(y) ), +1 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::invoke( &X::m, std::cref(y) ), -1 );
}
{
X const x = {};
BOOST_TEST_EQ( boost::compat::invoke( &X::m, x ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::m, &x ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::m, std::ref(x) ), -1 );
}
{
Y const y = {};
BOOST_TEST_EQ( boost::compat::invoke( &X::m, y ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::m, &y ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::m, std::ref(y) ), -1 );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,88 @@
// Copyright 2024 Peter Dimov
// 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/invoke.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
#define BOOST_TEST_EQ(x, y) STATIC_ASSERT((x) == (y))
struct X
{
constexpr int f0() const
{
return -1;
}
constexpr int f1( int x1 ) const noexcept
{
return x1;
}
constexpr int f2( int x1, int x2 ) const
{
return 10*x1+x2;
}
constexpr int f3( int x1, int x2, int x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
struct Y: public X
{
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::invoke( &X::f0, X() ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f1, X(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, X(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, X(), 1, 2, 3 ), 123 );
}
{
BOOST_TEST_EQ( boost::compat::invoke( &X::f0, Y() ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f1, Y(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, Y(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, Y(), 1, 2, 3 ), 123 );
}
{
constexpr X x = {};
BOOST_TEST_EQ( boost::compat::invoke( &X::f0, x ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f1, x, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f0, &x ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f1, &x, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, &x, 1, 2, 3 ), 123 );
}
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
{
constexpr Y y = {};
BOOST_TEST_EQ( boost::compat::invoke( &X::f0, y ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f1, y, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, y, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, y, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f0, &y ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f1, &y, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, &y, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, &y, 1, 2, 3 ), 123 );
}
#endif
}

View File

@@ -0,0 +1,134 @@
// Copyright 2024 Peter Dimov
// 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/invoke.hpp>
#include <boost/core/lightweight_test.hpp>
#include <functional>
struct X
{
int f0()
{
return -1;
}
int f1( int x1 ) noexcept
{
return x1;
}
int f2( int x1, int x2 ) const
{
return 10*x1+x2;
}
int f3( int x1, int x2, int x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
struct Y: public virtual X
{
};
int main()
{
{
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f0, X() ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f1, X(), 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f2, X(), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f3, X(), 1, 2, 3 ) ), true );
}
{
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f0, Y() ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f1, Y(), 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f2, Y(), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f3, Y(), 1, 2, 3 ) ), true );
}
{
X x;
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f0, x ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f1, x, 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f2, x, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f3, x, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f0, &x ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f1, &x, 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f2, &x, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f3, &x, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f0, std::ref(x) ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f1, std::ref(x), 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f2, std::ref(x), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f3, std::ref(x), 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f2, std::cref(x), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f3, std::cref(x), 1, 2, 3 ) ), true );
}
{
Y y;
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f0, y ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f1, y, 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f2, y, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f3, y, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f0, &y ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f1, &y, 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f2, &y, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f3, &y, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f0, std::ref(y) ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f1, std::ref(y), 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f2, std::ref(y), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f3, std::ref(y), 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f2, std::cref(y), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f3, std::cref(y), 1, 2, 3 ) ), true );
}
{
X const x = {};
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f2, x, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f3, x, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f2, &x, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f3, &x, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f2, std::ref(x), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f3, std::ref(x), 1, 2, 3 ) ), true );
}
{
Y const y = {};
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f2, y, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f3, y, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f2, &y, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f3, &y, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f2, std::ref(y), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( &X::f3, std::ref(y), 1, 2, 3 ) ), true );
}
return boost::report_errors();
}
#endif

127
test/invoke_mfn_test.cpp Normal file
View File

@@ -0,0 +1,127 @@
// Copyright 2024 Peter Dimov
// 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/invoke.hpp>
#include <boost/core/lightweight_test.hpp>
#include <functional>
struct X
{
int f0()
{
return -1;
}
int f1( int x1 ) noexcept
{
return x1;
}
int f2( int x1, int x2 ) const
{
return 10*x1+x2;
}
int f3( int x1, int x2, int x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
struct Y: public virtual X
{
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::invoke( &X::f0, X() ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f1, X(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, X(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, X(), 1, 2, 3 ), 123 );
}
{
BOOST_TEST_EQ( boost::compat::invoke( &X::f0, Y() ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f1, Y(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, Y(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, Y(), 1, 2, 3 ), 123 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::invoke( &X::f0, x ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f1, x, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f0, &x ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f1, &x, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, &x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f0, std::ref(x) ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f1, std::ref(x), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, std::ref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, std::ref(x), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, std::cref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, std::cref(x), 1, 2, 3 ), 123 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::invoke( &X::f0, y ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f1, y, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, y, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, y, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f0, &y ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f1, &y, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, &y, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, &y, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f0, std::ref(y) ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f1, std::ref(y), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, std::ref(y), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, std::ref(y), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, std::cref(y), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, std::cref(y), 1, 2, 3 ), 123 );
}
{
X const x = {};
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, &x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, std::ref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, std::ref(x), 1, 2, 3 ), 123 );
}
{
Y const y = {};
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, y, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, y, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, &y, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, &y, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f2, std::ref(y), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( &X::f3, std::ref(y), 1, 2, 3 ), 123 );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,50 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/invoke.hpp>
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
#define BOOST_TEST_EQ(x, y) STATIC_ASSERT((x) == (y))
struct F
{
constexpr int operator()() const
{
return -1;
}
constexpr int operator()( int x1 ) const noexcept
{
return x1;
}
constexpr int operator()( int x1, int x2 ) const
{
return 10*x1+x2;
}
constexpr int operator()( int x1, int x2, int x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::invoke( F() ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( F(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( F(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( F(), 1, 2, 3 ), 123 );
}
{
constexpr F f = {};
BOOST_TEST_EQ( boost::compat::invoke( f ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( f, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( f, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( f, 1, 2, 3 ), 123 );
}
}

View File

@@ -0,0 +1,57 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/invoke.hpp>
#include <boost/core/lightweight_test.hpp>
struct F
{
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;
}
};
int main()
{
{
BOOST_TEST_EQ( noexcept( boost::compat::invoke( F() ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( F(), 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( F(), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( F(), 1, 2, 3 ) ), true );
}
{
F f = {};
BOOST_TEST_EQ( noexcept( boost::compat::invoke( f ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( f, 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( f, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( f, 1, 2, 3 ) ), true );
}
{
F const f = {};
BOOST_TEST_EQ( noexcept( boost::compat::invoke( f, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke( f, 1, 2, 3 ) ), true );
}
return boost::report_errors();
}

57
test/invoke_obj_test.cpp Normal file
View File

@@ -0,0 +1,57 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/invoke.hpp>
#include <boost/core/lightweight_test.hpp>
struct F
{
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;
}
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::invoke( F() ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( F(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( F(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( F(), 1, 2, 3 ), 123 );
}
{
F f;
BOOST_TEST_EQ( boost::compat::invoke( f ), -1 );
BOOST_TEST_EQ( boost::compat::invoke( f, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke( f, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( f, 1, 2, 3 ), 123 );
}
{
F const f = {};
BOOST_TEST_EQ( boost::compat::invoke( f, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke( f, 1, 2, 3 ), 123 );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,50 @@
// Copyright 2024 Peter Dimov
// 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/invoke.hpp>
#include <boost/config.hpp>
#define STATIC_ASSERT(...) static_assert((__VA_ARGS__), #__VA_ARGS__)
#define BOOST_TEST_EQ(x, y) STATIC_ASSERT((x) == (y))
constexpr int f0()
{
return -1;
}
constexpr int f1( int x1 ) noexcept
{
return x1;
}
constexpr int f2( int x1, int x2 )
{
return 10*x1+x2;
}
constexpr int f3( int x1, int x2, int x3 ) noexcept
{
return 100*x1 + 10*x2 + x3;
}
int main()
{
BOOST_TEST_EQ( boost::compat::invoke_r<long>( f0 ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( f1, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( f2, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( f3, 1, 2, 3 ), 123 );
#if !defined(BOOST_NO_CXX14_CONSTEXPR)
STATIC_ASSERT( boost::compat::invoke_r<void>( f0 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( f1, 1 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( f2, 1, 2 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( f3, 1, 2, 3 ), true );
#endif
}

View File

@@ -0,0 +1,52 @@
// Copyright 2024 Peter Dimov
// 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/invoke.hpp>
#include <boost/core/lightweight_test.hpp>
int f0()
{
return -1;
}
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 main()
{
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( f0 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( f1, 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( f2, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( f3, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( f0 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( f1, 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( f2, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( f3, 1, 2, 3 ) ), true );
return boost::report_errors();
}
#endif

45
test/invoke_r_fn_test.cpp Normal file
View File

@@ -0,0 +1,45 @@
// Copyright 2024 Peter Dimov
// 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/invoke.hpp>
#include <boost/core/lightweight_test.hpp>
int f0()
{
return -1;
}
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 main()
{
BOOST_TEST_EQ( boost::compat::invoke_r<long>( f0 ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( f1, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( f2, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( f3, 1, 2, 3 ), 123 );
boost::compat::invoke_r<void>( f0 );
boost::compat::invoke_r<void>( f1, 1 );
boost::compat::invoke_r<void>( f2, 1, 2 );
boost::compat::invoke_r<void>( f3, 1, 2, 3 );
return boost::report_errors();
}

View File

@@ -0,0 +1,56 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/invoke.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#define STATIC_ASSERT(...) static_assert((__VA_ARGS__), #__VA_ARGS__)
#define BOOST_TEST_EQ(x, y) STATIC_ASSERT((x) == (y))
struct X
{
int m = -1;
};
struct Y: public X
{
};
int main()
{
{
constexpr X x = {};
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, X() ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, x ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, &x ), -1 );
#if !defined(BOOST_NO_CXX14_CONSTEXPR)
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::m, X() ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::m, x ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::m, &x ), true );
#endif
}
#if !BOOST_WORKAROUND(BOOST_MSVC, >= 1920 && BOOST_MSVC < 1950)
{
constexpr Y y = {};
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, Y() ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, y ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, &y ), -1 );
#if !defined(BOOST_NO_CXX14_CONSTEXPR)
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::m, Y() ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::m, y ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::m, &y ), true );
#endif
}
#endif
}

View File

@@ -0,0 +1,99 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/invoke.hpp>
#include <boost/core/lightweight_test.hpp>
#include <functional>
struct X
{
int m = -1;
};
struct Y: public virtual X
{
};
int main()
{
{
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::m, X() ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::m, Y() ) ), true );
}
{
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::m, X() ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::m, Y() ) ), true );
}
{
X x;
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::m, x ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::m, &x ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::m, std::ref(x) ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::m, std::cref(x) ) ), true );
}
{
X x;
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::m, x ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::m, &x ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::m, std::ref(x) ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::m, std::cref(x) ) ), true );
}
{
Y y;
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::m, y ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::m, &y ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::m, std::ref(y) ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::m, std::cref(y) ) ), true );
}
{
Y y;
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::m, y ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::m, &y ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::m, std::ref(y) ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::m, std::cref(y) ) ), true );
}
{
X const x = {};
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::m, x ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::m, &x ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::m, std::ref(x) ) ), true );
}
{
X const x = {};
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::m, x ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::m, &x ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::m, std::ref(x) ) ), true );
}
{
Y const y = {};
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::m, y ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::m, &y ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::m, std::ref(y) ) ), true );
}
{
Y const y = {};
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::m, y ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::m, &y ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::m, std::ref(y) ) ), true );
}
return boost::report_errors();
}

131
test/invoke_r_md_test.cpp Normal file
View File

@@ -0,0 +1,131 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/invoke.hpp>
#include <boost/core/lightweight_test.hpp>
#include <functional>
struct X
{
int m = -1;
};
struct Y: public virtual X
{
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, X() ), -1 );
}
{
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, Y() ), -1 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::invoke_r<int const&>( &X::m, x ), -1 );
boost::compat::invoke_r<int&>( &X::m, x ) = +1;
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, x ), +1 );
boost::compat::invoke_r<void>( &X::m, x );
}
{
X x;
BOOST_TEST_EQ( boost::compat::invoke_r<int const&>( &X::m, &x ), -1 );
boost::compat::invoke_r<int&>( &X::m, &x ) = +1;
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, &x ), +1 );
boost::compat::invoke_r<void>( &X::m, &x );
}
{
X x;
BOOST_TEST_EQ( boost::compat::invoke_r<int const&>( &X::m, std::ref(x) ), -1 );
boost::compat::invoke_r<int&>( &X::m, std::ref(x) ) = +1;
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, std::ref(x) ), +1 );
boost::compat::invoke_r<void>( &X::m, std::ref(x) );
}
{
X x;
BOOST_TEST_EQ( boost::compat::invoke_r<int const&>( &X::m, std::cref(x) ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, std::cref(x) ), -1 );
boost::compat::invoke_r<void>( &X::m, std::cref(x) );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::invoke_r<int const&>( &X::m, y ), -1 );
boost::compat::invoke_r<int&>( &X::m, y ) = +1;
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, y ), +1 );
boost::compat::invoke_r<void>( &X::m, y );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::invoke_r<int const&>( &X::m, &y ), -1 );
boost::compat::invoke_r<int&>( &X::m, &y ) = +1;
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, &y ), +1 );
boost::compat::invoke_r<void>( &X::m, &y );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::invoke_r<int const&>( &X::m, std::ref(y) ), -1 );
boost::compat::invoke_r<int&>( &X::m, std::ref(y) ) = +1;
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, std::ref(y) ), +1 );
boost::compat::invoke_r<void>( &X::m, std::ref(y) );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::invoke_r<int const&>( &X::m, std::cref(y) ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, std::cref(y) ), -1 );
boost::compat::invoke_r<void>( &X::m, std::cref(y) );
}
{
X const x = {};
BOOST_TEST_EQ( boost::compat::invoke_r<int const&>( &X::m, x ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, x ), -1 );
boost::compat::invoke_r<void>( &X::m, x );
BOOST_TEST_EQ( boost::compat::invoke_r<int const&>( &X::m, &x ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, &x ), -1 );
boost::compat::invoke_r<void>( &X::m, &x );
BOOST_TEST_EQ( boost::compat::invoke_r<int const&>( &X::m, std::ref(x) ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, std::ref(x) ), -1 );
boost::compat::invoke_r<void>( &X::m, std::ref(x) );
}
{
Y const y = {};
BOOST_TEST_EQ( boost::compat::invoke_r<int const&>( &X::m, y ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, y ), -1 );
boost::compat::invoke_r<void>( &X::m, y );
BOOST_TEST_EQ( boost::compat::invoke_r<int const&>( &X::m, &y ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, &y ), -1 );
boost::compat::invoke_r<void>( &X::m, &y );
BOOST_TEST_EQ( boost::compat::invoke_r<int const&>( &X::m, std::ref(y) ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::m, std::ref(y) ), -1 );
boost::compat::invoke_r<void>( &X::m, std::ref(y) );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,134 @@
// Copyright 2024 Peter Dimov
// 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/invoke.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#define STATIC_ASSERT(...) static_assert((__VA_ARGS__), #__VA_ARGS__)
#define BOOST_TEST_EQ(x, y) STATIC_ASSERT((x) == (y))
struct X
{
constexpr int f0() const
{
return -1;
}
constexpr int f1( int x1 ) const noexcept
{
return x1;
}
constexpr int f2( int x1, int x2 ) const
{
return 10*x1+x2;
}
constexpr int f3( int x1, int x2, int x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
struct Y: public X
{
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f0, X() ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f1, X(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, X(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, X(), 1, 2, 3 ), 123 );
#if !defined(BOOST_NO_CXX14_CONSTEXPR)
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f0, X() ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f1, X(), 1 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f2, X(), 1, 2 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f3, X(), 1, 2, 3 ), true );
#endif
}
{
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f0, Y() ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f1, Y(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, Y(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, Y(), 1, 2, 3 ), 123 );
#if !defined(BOOST_NO_CXX14_CONSTEXPR)
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f0, Y() ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f1, Y(), 1 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f2, Y(), 1, 2 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f3, Y(), 1, 2, 3 ), true );
#endif
}
{
constexpr X x = {};
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f0, x ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f1, x, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f0, &x ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f1, &x, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, &x, 1, 2, 3 ), 123 );
#if !defined(BOOST_NO_CXX14_CONSTEXPR)
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f0, x ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f1, x, 1 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f2, x, 1, 2 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f3, x, 1, 2, 3 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f0, &x ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f1, &x, 1 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f2, &x, 1, 2 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f3, &x, 1, 2, 3 ), true );
#endif
}
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
{
constexpr Y y = {};
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f0, y ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f1, y, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, y, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, y, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f0, &y ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f1, &y, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, &y, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, &y, 1, 2, 3 ), 123 );
#if !defined(BOOST_NO_CXX14_CONSTEXPR)
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f0, y ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f1, y, 1 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f2, y, 1, 2 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f3, y, 1, 2, 3 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f0, &y ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f1, &y, 1 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f2, &y, 1, 2 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( &X::f3, &y, 1, 2, 3 ), true );
#endif
}
#endif
}

View File

@@ -0,0 +1,214 @@
// Copyright 2024 Peter Dimov
// 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/invoke.hpp>
#include <boost/core/lightweight_test.hpp>
#include <functional>
struct X
{
int f0()
{
return -1;
}
int f1( int x1 ) noexcept
{
return x1;
}
int f2( int x1, int x2 ) const
{
return 10*x1+x2;
}
int f3( int x1, int x2, int x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
struct Y: public virtual X
{
};
int main()
{
{
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f0, X() ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f1, X(), 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f2, X(), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f3, X(), 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f0, X() ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f1, X(), 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f2, X(), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f3, X(), 1, 2, 3 ) ), true );
}
{
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f0, Y() ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f1, Y(), 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f2, Y(), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f3, Y(), 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f0, Y() ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f1, Y(), 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f2, Y(), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f3, Y(), 1, 2, 3 ) ), true );
}
{
X x;
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f0, x ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f1, x, 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f2, x, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f3, x, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f0, &x ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f1, &x, 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f2, &x, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f3, &x, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f0, std::ref(x) ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f1, std::ref(x), 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f2, std::ref(x), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f3, std::ref(x), 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f2, std::cref(x), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f3, std::cref(x), 1, 2, 3 ) ), true );
}
{
X x;
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f0, x ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f1, x, 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f2, x, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f3, x, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f0, &x ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f1, &x, 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f2, &x, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f3, &x, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f0, std::ref(x) ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f1, std::ref(x), 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f2, std::ref(x), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f3, std::ref(x), 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f2, std::cref(x), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f3, std::cref(x), 1, 2, 3 ) ), true );
}
{
Y y;
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f0, y ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f1, y, 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f2, y, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f3, y, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f0, &y ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f1, &y, 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f2, &y, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f3, &y, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f0, std::ref(y) ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f1, std::ref(y), 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f2, std::ref(y), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f3, std::ref(y), 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f2, std::cref(y), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f3, std::cref(y), 1, 2, 3 ) ), true );
}
{
Y y;
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f0, y ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f1, y, 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f2, y, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f3, y, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f0, &y ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f1, &y, 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f2, &y, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f3, &y, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f0, std::ref(y) ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f1, std::ref(y), 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f2, std::ref(y), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f3, std::ref(y), 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f2, std::cref(y), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f3, std::cref(y), 1, 2, 3 ) ), true );
}
{
X const x = {};
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f2, x, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f3, x, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f2, &x, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f3, &x, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f2, std::ref(x), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f3, std::ref(x), 1, 2, 3 ) ), true );
}
{
X const x = {};
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f2, x, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f3, x, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f2, &x, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f3, &x, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f2, std::ref(x), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f3, std::ref(x), 1, 2, 3 ) ), true );
}
{
Y const y = {};
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f2, y, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f3, y, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f2, &y, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f3, &y, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f2, std::ref(y), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( &X::f3, std::ref(y), 1, 2, 3 ) ), true );
}
{
Y const y = {};
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f2, y, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f3, y, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f2, &y, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f3, &y, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f2, std::ref(y), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( &X::f3, std::ref(y), 1, 2, 3 ) ), true );
}
return boost::report_errors();
}
#endif

211
test/invoke_r_mfn_test.cpp Normal file
View File

@@ -0,0 +1,211 @@
// Copyright 2024 Peter Dimov
// 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/invoke.hpp>
#include <boost/core/lightweight_test.hpp>
#include <functional>
struct X
{
int f0()
{
return -1;
}
int f1( int x1 ) noexcept
{
return x1;
}
int f2( int x1, int x2 ) const
{
return 10*x1+x2;
}
int f3( int x1, int x2, int x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
struct Y: public virtual X
{
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f0, X() ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f1, X(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, X(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, X(), 1, 2, 3 ), 123 );
}
{
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f0, Y() ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f1, Y(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, Y(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, Y(), 1, 2, 3 ), 123 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f0, x ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f1, x, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f0, &x ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f1, &x, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, &x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f0, std::ref(x) ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f1, std::ref(x), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, std::ref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, std::ref(x), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, std::cref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, std::cref(x), 1, 2, 3 ), 123 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f0, y ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f1, y, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, y, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, y, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f0, &y ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f1, &y, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, &y, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, &y, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f0, std::ref(y) ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f1, std::ref(y), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, std::ref(y), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, std::ref(y), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, std::cref(y), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, std::cref(y), 1, 2, 3 ), 123 );
}
{
X const x = {};
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, &x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, std::ref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, std::ref(x), 1, 2, 3 ), 123 );
}
{
Y const y = {};
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, y, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, y, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, &y, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, &y, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f2, std::ref(y), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( &X::f3, std::ref(y), 1, 2, 3 ), 123 );
}
{
boost::compat::invoke_r<void>( &X::f0, X() );
boost::compat::invoke_r<void>( &X::f1, X(), 1 );
boost::compat::invoke_r<void>( &X::f2, X(), 1, 2 );
boost::compat::invoke_r<void>( &X::f3, X(), 1, 2, 3 );
}
{
boost::compat::invoke_r<void>( &X::f0, Y() );
boost::compat::invoke_r<void>( &X::f1, Y(), 1 );
boost::compat::invoke_r<void>( &X::f2, Y(), 1, 2 );
boost::compat::invoke_r<void>( &X::f3, Y(), 1, 2, 3 );
}
{
X x;
boost::compat::invoke_r<void>( &X::f0, x );
boost::compat::invoke_r<void>( &X::f1, x, 1 );
boost::compat::invoke_r<void>( &X::f2, x, 1, 2 );
boost::compat::invoke_r<void>( &X::f3, x, 1, 2, 3 );
boost::compat::invoke_r<void>( &X::f0, &x );
boost::compat::invoke_r<void>( &X::f1, &x, 1 );
boost::compat::invoke_r<void>( &X::f2, &x, 1, 2 );
boost::compat::invoke_r<void>( &X::f3, &x, 1, 2, 3 );
boost::compat::invoke_r<void>( &X::f0, std::ref(x) );
boost::compat::invoke_r<void>( &X::f1, std::ref(x), 1 );
boost::compat::invoke_r<void>( &X::f2, std::ref(x), 1, 2 );
boost::compat::invoke_r<void>( &X::f3, std::ref(x), 1, 2, 3 );
boost::compat::invoke_r<void>( &X::f2, std::cref(x), 1, 2 );
boost::compat::invoke_r<void>( &X::f3, std::cref(x), 1, 2, 3 );
}
{
Y y;
boost::compat::invoke_r<void>( &X::f0, y );
boost::compat::invoke_r<void>( &X::f1, y, 1 );
boost::compat::invoke_r<void>( &X::f2, y, 1, 2 );
boost::compat::invoke_r<void>( &X::f3, y, 1, 2, 3 );
boost::compat::invoke_r<void>( &X::f0, &y );
boost::compat::invoke_r<void>( &X::f1, &y, 1 );
boost::compat::invoke_r<void>( &X::f2, &y, 1, 2 );
boost::compat::invoke_r<void>( &X::f3, &y, 1, 2, 3 );
boost::compat::invoke_r<void>( &X::f0, std::ref(y) );
boost::compat::invoke_r<void>( &X::f1, std::ref(y), 1 );
boost::compat::invoke_r<void>( &X::f2, std::ref(y), 1, 2 );
boost::compat::invoke_r<void>( &X::f3, std::ref(y), 1, 2, 3 );
boost::compat::invoke_r<void>( &X::f2, std::cref(y), 1, 2 );
boost::compat::invoke_r<void>( &X::f3, std::cref(y), 1, 2, 3 );
}
{
X const x = {};
boost::compat::invoke_r<void>( &X::f2, x, 1, 2 );
boost::compat::invoke_r<void>( &X::f3, x, 1, 2, 3 );
boost::compat::invoke_r<void>( &X::f2, &x, 1, 2 );
boost::compat::invoke_r<void>( &X::f3, &x, 1, 2, 3 );
boost::compat::invoke_r<void>( &X::f2, std::ref(x), 1, 2 );
boost::compat::invoke_r<void>( &X::f3, std::ref(x), 1, 2, 3 );
}
{
Y const y = {};
boost::compat::invoke_r<long>( &X::f2, y, 1, 2 );
boost::compat::invoke_r<long>( &X::f3, y, 1, 2, 3 );
boost::compat::invoke_r<long>( &X::f2, &y, 1, 2 );
boost::compat::invoke_r<long>( &X::f3, &y, 1, 2, 3 );
boost::compat::invoke_r<long>( &X::f2, std::ref(y), 1, 2 );
boost::compat::invoke_r<long>( &X::f3, std::ref(y), 1, 2, 3 );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,68 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/invoke.hpp>
#define STATIC_ASSERT(...) static_assert((__VA_ARGS__), #__VA_ARGS__)
#define BOOST_TEST_EQ(x, y) STATIC_ASSERT((x) == (y))
struct F
{
constexpr int operator()() const
{
return -1;
}
constexpr int operator()( int x1 ) const noexcept
{
return x1;
}
constexpr int operator()( int x1, int x2 ) const
{
return 10*x1+x2;
}
constexpr int operator()( int x1, int x2, int x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::invoke_r<long>( F() ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( F(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( F(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( F(), 1, 2, 3 ), 123 );
#if !defined(BOOST_NO_CXX14_CONSTEXPR)
STATIC_ASSERT( boost::compat::invoke_r<void>( F() ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( F(), 1 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( F(), 1, 2 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( F(), 1, 2, 3 ), true );
#endif
}
{
constexpr F f = {};
BOOST_TEST_EQ( boost::compat::invoke_r<long>( f ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( f, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( f, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( f, 1, 2, 3 ), 123 );
#if !defined(BOOST_NO_CXX14_CONSTEXPR)
STATIC_ASSERT( boost::compat::invoke_r<void>( f ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( f, 1 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( f, 1, 2 ), true );
STATIC_ASSERT( boost::compat::invoke_r<void>( f, 1, 2, 3 ), true );
#endif
}
}

View File

@@ -0,0 +1,70 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/invoke.hpp>
#include <boost/core/lightweight_test.hpp>
struct F
{
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;
}
};
int main()
{
{
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( F() ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( F(), 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( F(), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( F(), 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( F() ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( F(), 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( F(), 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( F(), 1, 2, 3 ) ), true );
}
{
F f = {};
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( f ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( f, 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( f, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( f, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( f ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( f, 1 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( f, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( f, 1, 2, 3 ) ), true );
}
{
F const f = {};
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( f, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<long>( f, 1, 2, 3 ) ), true );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( f, 1, 2 ) ), false );
BOOST_TEST_EQ( noexcept( boost::compat::invoke_r<void>( f, 1, 2, 3 ) ), true );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,80 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/invoke.hpp>
#include <boost/core/lightweight_test.hpp>
struct F
{
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;
}
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::invoke_r<long>( F() ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( F(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( F(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( F(), 1, 2, 3 ), 123 );
}
{
F f;
BOOST_TEST_EQ( boost::compat::invoke_r<long>( f ), -1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( f, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( f, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( f, 1, 2, 3 ), 123 );
}
{
F const f = {};
BOOST_TEST_EQ( boost::compat::invoke_r<long>( f, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::invoke_r<long>( f, 1, 2, 3 ), 123 );
}
{
boost::compat::invoke_r<void>( F() );
boost::compat::invoke_r<void>( F(), 1 );
boost::compat::invoke_r<void>( F(), 1, 2 );
boost::compat::invoke_r<void>( F(), 1, 2, 3 );
}
{
F f;
boost::compat::invoke_r<void>( f );
boost::compat::invoke_r<void>( f, 1 );
boost::compat::invoke_r<void>( f, 1, 2 );
boost::compat::invoke_r<void>( f, 1, 2, 3 );
}
{
F const f = {};
boost::compat::invoke_r<void>( f, 1, 2 );
boost::compat::invoke_r<void>( f, 1, 2, 3 );
}
return boost::report_errors();
}

107
test/invoke_result_test.cpp Normal file
View File

@@ -0,0 +1,107 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/invoke.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/mp11/utility.hpp>
struct F
{
void operator()()
{
}
char operator()( char x1 ) noexcept
{
return x1;
}
int operator()( int x1, int x2 ) const
{
return 10*x1+x2;
}
double operator()( float x1, float x2, float x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
struct X
{
};
int main()
{
using boost::compat::invoke_result_t;
using boost::mp11::mp_valid;
// nonfunction
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, int> ));
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, int, int> ));
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, int, int, int> ));
// function reference
BOOST_TEST_TRAIT_SAME( invoke_result_t<void(&)()>, void );
BOOST_TEST_TRAIT_SAME( invoke_result_t<char(&)(int), char>, char );
BOOST_TEST_TRAIT_SAME( invoke_result_t<int(&)(int, int), int, int>, int );
BOOST_TEST_TRAIT_SAME( invoke_result_t<double(&)(double, double, double), float, float, float>, double );
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, void(&)(), int> ));
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, char(&)(int)> ));
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, char(&)(int), int, int> ));
// function pointer
BOOST_TEST_TRAIT_SAME( invoke_result_t<void(*)()>, void );
BOOST_TEST_TRAIT_SAME( invoke_result_t<char(*)(int), char>, char );
BOOST_TEST_TRAIT_SAME( invoke_result_t<int(*)(int, int), int, int>, int );
BOOST_TEST_TRAIT_SAME( invoke_result_t<double(*)(double, double, double), float, float, float>, double );
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, void(*)(), int> ));
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, char(*)(int)> ));
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, char(*)(int), int, int> ));
// object
BOOST_TEST_TRAIT_SAME( invoke_result_t<F>, void );
BOOST_TEST_TRAIT_SAME( invoke_result_t<F, char>, char );
BOOST_TEST_TRAIT_SAME( invoke_result_t<F, int, int>, int );
BOOST_TEST_TRAIT_SAME( invoke_result_t<F, float, float, float>, double );
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, F, int, int, int, int> ));
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, F const> ));
// member function pointer
BOOST_TEST_TRAIT_SAME( invoke_result_t<void(X::*)(), X>, void );
BOOST_TEST_TRAIT_SAME( invoke_result_t<char(X::*)(int), X, char>, char );
BOOST_TEST_TRAIT_SAME( invoke_result_t<int(X::*)(int, int), X, int, int>, int );
BOOST_TEST_TRAIT_SAME( invoke_result_t<double(X::*)(double, double, double), X, float, float, float>, double );
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, void(X::*)()> ));
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, void(X::*)(), int> ));
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, void(X::*)(), X, int> ));
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, char(X::*)(int)> ));
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, char(X::*)(int), int> ));
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, char(X::*)(int), X> ));
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, char(X::*)(int), X, int, int> ));
// member data pointer
BOOST_TEST_TRAIT_SAME( invoke_result_t<int X::*, X>, int&& );
BOOST_TEST_TRAIT_SAME( invoke_result_t<int X::*, X const>, int const&& );
BOOST_TEST_TRAIT_SAME( invoke_result_t<int X::*, X&>, int& );
BOOST_TEST_TRAIT_SAME( invoke_result_t<int X::*, X const&>, int const& );
BOOST_TEST_TRAIT_SAME( invoke_result_t<int X::*, X*>, int& );
BOOST_TEST_TRAIT_SAME( invoke_result_t<int X::*, X const*>, int const& );
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, int X::*> ));
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, int X::*, int> ));
BOOST_TEST_TRAIT_FALSE(( mp_valid<invoke_result_t, int X::*, X, int> ));
return boost::report_errors();
}

View File

@@ -0,0 +1,195 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/invoke.hpp>
#include <boost/core/lightweight_test_trait.hpp>
struct F
{
void operator()()
{
}
char operator()( char x1 ) noexcept
{
return x1;
}
int operator()( int x1, int x2 ) const
{
return 10*x1+x2;
}
double operator()( float x1, float x2, float x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
struct X
{
};
int main()
{
using boost::compat::is_invocable_r;
// nonfunction
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, int, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, int, int, int> ));
// function reference
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, void(&)()> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<long, char(&)(int), char> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<long, int(&)(int, int), int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<long, double(&)(double, double, double), float, float, float> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, void(&)()> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, char(&)(int), char> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, int(&)(int, int), int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, double(&)(double, double, double), float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, void(&)()> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, char(&)(int), char> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, int(&)(int, int), int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, double(&)(double, double, double), float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, void(&)(), int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, char(&)(int)> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, char(&)(int), int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, void(&)(), int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, char(&)(int)> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, char(&)(int), int, int> ));
// function pointer
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, void(*)()> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<long, char(*)(int), char> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<long, int(*)(int, int), int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<long, double(*)(double, double, double), float, float, float> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, void(*)()> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, char(*)(int), char> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, int(*)(int, int), int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, double(*)(double, double, double), float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, void(*)()> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, char(*)(int), char> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, int(*)(int, int), int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, double(*)(double, double, double), float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, void(*)(), int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, char(*)(int)> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, char(*)(int), int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, void(*)(), int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, char(*)(int)> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, char(*)(int), int, int> ));
// object
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, F> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<long, F, char> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<long, F, int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<long, F, float, float, float> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, F> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, F, char> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, F, int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, F, float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, F> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, F, char> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, F, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, F, float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, F, int, int, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, F const> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, F, int, int, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, F const> ));
// member function pointer
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, void(X::*)(), X> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<long, char(X::*)(int), X, char> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<long, int(X::*)(int, int), X, int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<long, double(X::*)(double, double, double), X, float, float, float> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, void(X::*)(), X> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, char(X::*)(int), X, char> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, int(X::*)(int, int), X, int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, double(X::*)(double, double, double), X, float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, void(X::*)(), X> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, char(X::*)(int), X, char> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, int(X::*)(int, int), X, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, double(X::*)(double, double, double), X, float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, void(X::*)()> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, void(X::*)(), int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, void(X::*)(), X, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, char(X::*)(int)> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, char(X::*)(int), int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, char(X::*)(int), X> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, char(X::*)(int), X, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, void(X::*)()> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, void(X::*)(), int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, void(X::*)(), X, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, char(X::*)(int)> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, char(X::*)(int), int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, char(X::*)(int), X> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, char(X::*)(int), X, int, int> ));
// member data pointer
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<long, int X::*, X> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<long, int X::*, X const> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<long, int X::*, X&> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<long, int X::*, X const&> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<long, int X::*, X*> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<long, int X::*, X const*> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, int X::*, X> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, int X::*, X const> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, int X::*, X&> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, int X::*, X const&> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, int X::*, X*> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<void, int X::*, X const*> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, int X::*, X> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, int X::*, X const> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, int X::*, X&> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, int X::*, X const&> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, int X::*, X*> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<X, int X::*, X const*> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<int&, int X::*, X> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<int&, int X::*, X const> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<int&, int X::*, X&> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<int&, int X::*, X const&> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<int&, int X::*, X*> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<int&, int X::*, X const*> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable_r<int&&, int X::*, X> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, int X::*> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, int X::*, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<long, int X::*, X, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, int X::*> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, int X::*, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable_r<void, int X::*, X, int> ));
return boost::report_errors();
}

105
test/is_invocable_test.cpp Normal file
View File

@@ -0,0 +1,105 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/invoke.hpp>
#include <boost/core/lightweight_test_trait.hpp>
struct F
{
void operator()()
{
}
char operator()( char x1 ) noexcept
{
return x1;
}
int operator()( int x1, int x2 ) const
{
return 10*x1+x2;
}
double operator()( float x1, float x2, float x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
struct X
{
};
int main()
{
using boost::compat::is_invocable;
// nonfunction
BOOST_TEST_TRAIT_FALSE(( is_invocable<int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<int, int, int> ));
// function reference
BOOST_TEST_TRAIT_TRUE(( is_invocable<void(&)()> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable<char(&)(int), char> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable<int(&)(int, int), int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable<double(&)(double, double, double), float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<void(&)(), int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<char(&)(int)> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<char(&)(int), int, int> ));
// function pointer
BOOST_TEST_TRAIT_TRUE(( is_invocable<void(*)()> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable<char(*)(int), char> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable<int(*)(int, int), int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable<double(*)(double, double, double), float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<void(*)(), int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<char(*)(int)> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<char(*)(int), int, int> ));
// object
BOOST_TEST_TRAIT_TRUE(( is_invocable<F> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable<F, char> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable<F, int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable<F, float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<F, int, int, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<F const> ));
// member function pointer
BOOST_TEST_TRAIT_TRUE(( is_invocable<void(X::*)(), X> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable<char(X::*)(int), X, char> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable<int(X::*)(int, int), X, int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable<double(X::*)(double, double, double), X, float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<void(X::*)()> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<void(X::*)(), int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<void(X::*)(), X, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<char(X::*)(int)> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<char(X::*)(int), int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<char(X::*)(int), X> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<char(X::*)(int), X, int, int> ));
// member data pointer
BOOST_TEST_TRAIT_TRUE(( is_invocable<int X::*, X> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable<int X::*, X const> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable<int X::*, X&> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable<int X::*, X const&> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable<int X::*, X*> ));
BOOST_TEST_TRAIT_TRUE(( is_invocable<int X::*, X const*> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<int X::*> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<int X::*, int> ));
BOOST_TEST_TRAIT_FALSE(( is_invocable<int X::*, X, int> ));
return boost::report_errors();
}

View File

@@ -0,0 +1,288 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/invoke.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
struct F
{
void operator()()
{
}
char operator()( char x1 ) noexcept
{
return x1;
}
int operator()( int x1, int x2 ) const
{
return 10*x1+x2;
}
double operator()( float x1, float x2, float x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
struct X
{
};
struct Y
{
Y( int );
Y( double ) noexcept;
};
int main()
{
using boost::compat::is_nothrow_invocable_r;
// nonfunction
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, int, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, int, int, int> ));
// function reference
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, void(&)()> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, char(&)(int), char> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, int(&)(int, int), int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, double(&)(double, double, double), float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, void(&)()> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, char(&)(int), char> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, int(&)(int, int), int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, double(&)(double, double, double), float, float, float> ));
#if defined(__cpp_noexcept_function_type)
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, void(&)() noexcept> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<long, char(&)(int) noexcept, char> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<long, int(&)(int, int) noexcept, int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<long, double(&)(double, double, double) noexcept, float, float, float> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, void(&)() noexcept> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, char(&)(int) noexcept, char> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, int(&)(int, int) noexcept, int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, double(&)(double, double, double) noexcept, float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, void(&)() noexcept> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, char(&)(int) noexcept, char> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, int(&)(int, int) noexcept, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, double(&)(double, double, double) noexcept, float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<Y, void(&)() noexcept> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<Y, char(&)(int) noexcept, char> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<Y, int(&)(int, int) noexcept, int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<Y, double(&)(double, double, double) noexcept, float, float, float> ));
#endif
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, void(&)(), int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, char(&)(int)> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, char(&)(int), int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, void(&)(), int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, char(&)(int)> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, char(&)(int), int, int> ));
// function pointer
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, void(*)()> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, char(*)(int), char> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, int(*)(int, int), int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, double(*)(double, double, double), float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, void(*)()> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, char(*)(int), char> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, int(*)(int, int), int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, double(*)(double, double, double), float, float, float> ));
#if defined(__cpp_noexcept_function_type)
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, void(*)() noexcept> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<long, char(*)(int) noexcept, char> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<long, int(*)(int, int) noexcept, int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<long, double(*)(double, double, double) noexcept, float, float, float> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, void(*)() noexcept> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, char(*)(int) noexcept, char> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, int(*)(int, int) noexcept, int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, double(*)(double, double, double) noexcept, float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, void(*)() noexcept> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, char(*)(int) noexcept, char> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, int(*)(int, int) noexcept, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, double(*)(double, double, double) noexcept, float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<Y, void(*)() noexcept> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<Y, char(*)(int) noexcept, char> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<Y, int(*)(int, int) noexcept, int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<Y, double(*)(double, double, double) noexcept, float, float, float> ));
#endif
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, void(*)(), int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, char(*)(int)> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, char(*)(int), int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, void(*)(), int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, char(*)(int)> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, char(*)(int), int, int> ));
// object
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, F> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, F, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, F> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, F, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, F> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, F, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<Y, F> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<Y, F, int, int> ));
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<long, F, char> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<long, F, float, float, float> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, F, char> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, F, float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, F, char> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, F, float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<Y, F, char> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<Y, F, float, float, float> ));
#endif
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, F, int, int, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, F const> ));
// member function pointer
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, void(X::*)(), X> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, char(X::*)(int), X, char> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, int(X::*)(int, int), X, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, double(X::*)(double, double, double), X, float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, void(X::*)(), X> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, char(X::*)(int), X, char> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, int(X::*)(int, int), X, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, double(X::*)(double, double, double), X, float, float, float> ));
#if defined(__cpp_noexcept_function_type)
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, void(X::*)() noexcept, X> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<long, char(X::*)(int) noexcept, X, char> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<long, int(X::*)(int, int) noexcept, X, int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<long, double(X::*)(double, double, double) noexcept, X, float, float, float> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, void(X::*)() noexcept, X> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, char(X::*)(int) noexcept, X, char> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, int(X::*)(int, int) noexcept, X, int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, double(X::*)(double, double, double) noexcept, X, float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, void(X::*)() noexcept, X> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, char(X::*)(int) noexcept, X, char> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, int(X::*)(int, int) noexcept, X, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, double(X::*)(double, double, double) noexcept, X, float, float, float> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<Y, void(X::*)() noexcept, X> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<Y, char(X::*)(int) noexcept, X, char> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<Y, int(X::*)(int, int) noexcept, X, int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<Y, double(X::*)(double, double, double) noexcept, X, float, float, float> ));
#endif
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, void(X::*)()> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, void(X::*)(), int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, void(X::*)(), X, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, char(X::*)(int)> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, char(X::*)(int), int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, char(X::*)(int), X> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, char(X::*)(int), X, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, void(X::*)()> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, void(X::*)(), int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, void(X::*)(), X, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, char(X::*)(int)> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, char(X::*)(int), int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, char(X::*)(int), X> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, char(X::*)(int), X, int, int> ));
// member data pointer
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<long, int X::*, X> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<long, int X::*, X const> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<long, int X::*, X&> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<long, int X::*, X const&> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<long, int X::*, X*> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<long, int X::*, X const*> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, int X::*, X> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, int X::*, X const> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, int X::*, X&> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, int X::*, X const&> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, int X::*, X*> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<void, int X::*, X const*> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, int X::*, X> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, int X::*, X const> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, int X::*, X&> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, int X::*, X const&> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, int X::*, X*> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<X, int X::*, X const*> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<Y, int X::*, X> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<Y, int X::*, X const> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<Y, int X::*, X&> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<Y, int X::*, X const&> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<Y, int X::*, X*> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<Y, int X::*, X const*> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<Y, double X::*, X> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<Y, double X::*, X const> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<Y, double X::*, X&> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<Y, double X::*, X const&> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<Y, double X::*, X*> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<Y, double X::*, X const*> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<int&, int X::*, X> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<int&, int X::*, X const> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<int&, int X::*, X&> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<int&, int X::*, X const&> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<int&, int X::*, X*> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<int&, int X::*, X const*> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable_r<int&&, int X::*, X> ));
#endif
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, int X::*> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, int X::*, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<long, int X::*, X, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, int X::*> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, int X::*, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable_r<void, int X::*, X, int> ));
return boost::report_errors();
}

View File

@@ -0,0 +1,143 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/invoke.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
struct F
{
void operator()()
{
}
char operator()( char x1 ) noexcept
{
return x1;
}
int operator()( int x1, int x2 ) const
{
return 10*x1+x2;
}
double operator()( float x1, float x2, float x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
struct X
{
};
int main()
{
using boost::compat::is_nothrow_invocable;
// nonfunction
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<int, int, int> ));
// function reference
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<void(&)()> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<char(&)(int), char> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<int(&)(int, int), int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<double(&)(double, double, double), float, float, float> ));
#if defined(__cpp_noexcept_function_type)
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<void(&)() noexcept> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<char(&)(int) noexcept, char> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<int(&)(int, int) noexcept, int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<double(&)(double, double, double) noexcept, float, float, float> ));
#endif
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<void(&)(), int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<char(&)(int)> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<char(&)(int), int, int> ));
// function pointer
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<void(*)()> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<char(*)(int), char> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<int(*)(int, int), int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<double(*)(double, double, double), float, float, float> ));
#if defined(__cpp_noexcept_function_type)
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<void(*)() noexcept> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<char(*)(int) noexcept, char> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<int(*)(int, int) noexcept, int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<double(*)(double, double, double) noexcept, float, float, float> ));
#endif
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<void(*)(), int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<char(*)(int)> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<char(*)(int), int, int> ));
// object
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<F> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<F, int, int> ));
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<F, char> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<F, float, float, float> ));
#endif
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<F, int, int, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<F const> ));
// member function pointer
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<void(X::*)(), X> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<char(X::*)(int), X, char> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<int(X::*)(int, int), X, int, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<double(X::*)(double, double, double), X, float, float, float> ));
#if defined(__cpp_noexcept_function_type)
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<void(X::*)() noexcept, X> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<char(X::*)(int) noexcept, X, char> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<int(X::*)(int, int) noexcept, X, int, int> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<double(X::*)(double, double, double) noexcept, X, float, float, float> ));
#endif
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<void(X::*)()> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<void(X::*)(), int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<void(X::*)(), X, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<char(X::*)(int)> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<char(X::*)(int), int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<char(X::*)(int), X> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<char(X::*)(int), X, int, int> ));
// member data pointer
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1910)
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<int X::*, X> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<int X::*, X const> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<int X::*, X&> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<int X::*, X const&> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<int X::*, X*> ));
BOOST_TEST_TRAIT_TRUE(( is_nothrow_invocable<int X::*, X const*> ));
#endif
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<int X::*> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<int X::*, int> ));
BOOST_TEST_TRAIT_FALSE(( is_nothrow_invocable<int X::*, X, int> ));
return boost::report_errors();
}

105
test/mem_fn_md_test.cpp Normal file
View File

@@ -0,0 +1,105 @@
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/mem_fn.hpp>
#include <boost/core/lightweight_test.hpp>
#include <functional>
struct X
{
int m = -1;
};
struct Y: public virtual X
{
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( X() ), -1 );
}
{
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( Y() ), -1 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( x ), -1 );
boost::compat::mem_fn( &X::m )( x ) = +1;
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( x ), +1 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( &x ), -1 );
boost::compat::mem_fn( &X::m )( &x ) = +1;
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( &x ), +1 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( std::ref(x) ), -1 );
boost::compat::mem_fn( &X::m )( std::ref(x) ) = +1;
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( std::ref(x) ), +1 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( std::cref(x) ), -1 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( y ), -1 );
boost::compat::mem_fn( &X::m )( y ) = +1;
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( y ), +1 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( &y ), -1 );
boost::compat::mem_fn( &X::m )( &y ) = +1;
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( &y ), +1 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( std::ref(y) ), -1 );
boost::compat::mem_fn( &X::m )( std::ref(y) ) = +1;
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( std::ref(y) ), +1 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( std::cref(y) ), -1 );
}
{
X const x = {};
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( x ), -1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( &x ), -1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( std::ref(x) ), -1 );
}
{
Y const y = {};
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( y ), -1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( &y ), -1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::m )( std::ref(y) ), -1 );
}
return boost::report_errors();
}

127
test/mem_fn_mfn_test.cpp Normal file
View File

@@ -0,0 +1,127 @@
// Copyright 2024 Peter Dimov
// 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/mem_fn.hpp>
#include <boost/core/lightweight_test.hpp>
#include <functional>
struct X
{
int f0()
{
return -1;
}
int f1( int x1 ) noexcept
{
return x1;
}
int f2( int x1, int x2 ) const
{
return 10*x1+x2;
}
int f3( int x1, int x2, int x3 ) const noexcept
{
return 100*x1 + 10*x2 + x3;
}
};
struct Y: public virtual X
{
};
int main()
{
{
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f0 )( X() ), -1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f1 )( X(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f2 )( X(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f3 )( X(), 1, 2, 3 ), 123 );
}
{
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f0 )( Y() ), -1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f1 )( Y(), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f2 )( Y(), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f3 )( Y(), 1, 2, 3 ), 123 );
}
{
X x;
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f0 )( x ), -1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f1 )( x, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f2 )( x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f3 )( x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f0 )( &x ), -1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f1 )( &x, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f2 )( &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f3 )( &x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f0 )( std::ref(x) ), -1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f1 )( std::ref(x), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f2 )( std::ref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f3 )( std::ref(x), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f2 )( std::cref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f3 )( std::cref(x), 1, 2, 3 ), 123 );
}
{
Y y;
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f0 )( y ), -1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f1 )( y, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f2 )( y, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f3 )( y, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f0 )( &y ), -1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f1 )( &y, 1 ), 1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f2 )( &y, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f3 )( &y, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f0 )( std::ref(y) ), -1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f1 )( std::ref(y), 1 ), 1 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f2 )( std::ref(y), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f3 )( std::ref(y), 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f2 )( std::cref(y), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f3 )( std::cref(y), 1, 2, 3 ), 123 );
}
{
X const x = {};
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f2 )( x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f3 )( x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f2 )( &x, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f3 )( &x, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f2 )( std::ref(x), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f3 )( std::ref(x), 1, 2, 3 ), 123 );
}
{
Y const y = {};
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f2 )( y, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f3 )( y, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f2 )( &y, 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f3 )( &y, 1, 2, 3 ), 123 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f2 )( std::ref(y), 1, 2 ), 12 );
BOOST_TEST_EQ( boost::compat::mem_fn( &X::f3 )( std::ref(y), 1, 2, 3 ), 123 );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,855 @@
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#if BOOST_WORKAROUND(BOOST_GCC, >= 7 * 10000 && BOOST_GCC < 8 * 10000)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wnoexcept-type"
#endif
#include <boost/compat/move_only_function.hpp>
#include <boost/compat/invoke.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <functional>
#include <memory>
#include <type_traits>
#if BOOST_WORKAROUND(BOOST_GCC, >= 13 * 10000)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wself-move"
#elif defined(BOOST_CLANG)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wself-move"
#endif
using std::is_same;
using std::is_constructible;
using std::is_nothrow_constructible;
using boost::compat::move_only_function;
using boost::compat::in_place_type_t;
// using std::move_only_function;
// using std::in_place_type_t;
using boost::compat::invoke_result_t;
using boost::compat::is_invocable;
using boost::compat::is_nothrow_invocable;
template<class T>
using add_const_t = typename std::add_const<T>::type;
template<class T>
constexpr add_const_t<T>& as_const_ref( T& t ) noexcept
{
return t;
}
void func0() {}
int func1()
{
return 1;
}
int func2( int x )
{
return x + 1;
}
int func3( std::unique_ptr<int> x )
{
return *x + 1;
}
template<class T, class ...Args>
std::unique_ptr<T> make_unique( Args&&... args )
{
return std::unique_ptr<T>( new T( std::forward<Args>( args )... ) );
}
struct callable
{
std::unique_ptr<int> p_ = make_unique<int>( 1 );
callable() = default;
callable( std::unique_ptr<int> p ): p_( std::move( p ) )
{
}
callable( std::initializer_list<int> il, int x, int y, int z )
{
int sum = 0;
for( auto const v : il )
{
sum += v;
}
sum += x;
sum += y;
sum += z;
p_ = make_unique<int>( sum );
}
callable( callable&& rhs ) noexcept
{
p_ = make_unique<int>( *rhs.p_ );
}
int operator()( int x )
{
return *p_ + x;
}
};
struct noex_callable
{
std::unique_ptr<int> p_ = make_unique<int>( 1 );
noex_callable() = default;
noex_callable( noex_callable&& rhs ) noexcept
{
p_ = make_unique<int>( *rhs.p_ );
}
noex_callable( noex_callable const& )
{
}
int operator()( int x ) noexcept
{
return *p_ + x;
}
};
struct large_callable
{
unsigned char padding[ 256 ] = {};
std::unique_ptr<int> p_ = make_unique<int>( 1 );
large_callable() = default;
large_callable( std::unique_ptr<int> p ): p_( std::move( p ) )
{
}
large_callable( large_callable&& rhs ) noexcept
{
p_ = make_unique<int>( *rhs.p_ );
}
int operator()( int x )
{
return *p_ + x;
}
int operator()( int x, int y )
{
return x + y;
}
};
struct person
{
std::string name_;
int age_ = -1;
std::unique_ptr<int> p_ = make_unique<int>( 1 );
int age()
{
return age_;
}
};
static void test_call()
{
{
move_only_function<int()> f1;
BOOST_TEST( !f1 );
move_only_function<int() const> f2;
BOOST_TEST( !f2 );
}
{
move_only_function<int()> f1( nullptr );
BOOST_TEST( !f1 );
move_only_function<int() const> f2( nullptr );
BOOST_TEST( !f2 );
}
{
move_only_function<void()> f1( func0 );
f1();
BOOST_TEST( f1 );
move_only_function<void() const> f2( func0 );
f2();
BOOST_TEST( f2 );
}
{
int ( *fp )() = [] { return 0; };
move_only_function<int()> f1( fp );
BOOST_TEST( f1 );
BOOST_TEST_EQ( f1(), 0 );
BOOST_TEST_EQ( std::move( f1() ), 0 );
move_only_function<int() const> f2( fp );
BOOST_TEST( f2 );
BOOST_TEST_EQ( f2(), 0 );
BOOST_TEST_EQ( std::move( f2() ), 0 );
fp = nullptr;
move_only_function<int() const> f3( fp );
BOOST_TEST_NOT( f3 );
}
{
struct declared;
enum class integer : int;
move_only_function<void(declared)> f1;
move_only_function<void(declared&)> f2;
move_only_function<void(declared&&)> f3;
move_only_function<void(integer)> f4;
}
{
move_only_function<int()> f1( func1 );
BOOST_TEST( f1 );
BOOST_TEST_EQ( f1(), 1 );
BOOST_TEST_EQ( std::move( f1() ), 1 );
move_only_function<int() const> f2( func1 );
BOOST_TEST( f2 );
BOOST_TEST_EQ( f2(), 1 );
BOOST_TEST_EQ( std::move( f2() ), 1 );
}
{
move_only_function<int( std::unique_ptr<int> )> fn( func3 );
BOOST_TEST_EQ( fn( make_unique<int>( 1 ) ), 2 );
BOOST_TEST_EQ( std::move( fn )( make_unique<int>( 1 ) ), 2 );
auto x = make_unique<int>( 1 );
BOOST_TEST( fn );
BOOST_TEST_EQ( fn( std::move( x ) ), 2 );
}
{
auto l = []() { return 1; };
move_only_function<int()> f1( l );
BOOST_TEST( f1 );
BOOST_TEST_EQ( f1(), 1 );
BOOST_TEST_EQ( std::move( f1 )(), 1 );
move_only_function<int() const> f2( l );
BOOST_TEST( f2 );
BOOST_TEST_EQ( f2(), 1 );
BOOST_TEST_EQ( as_const_ref( f2 )(), 1 );
BOOST_TEST_EQ( std::move( f2 )(), 1 );
BOOST_TEST_EQ( std::move( as_const_ref( f2 ) )(), 1 );
}
{
move_only_function<int()> f1( []() { return 1; } );
BOOST_TEST( f1 );
BOOST_TEST_EQ( f1(), 1 );
BOOST_TEST_EQ( std::move( f1 )(), 1 );
move_only_function<int() const> f2( []() { return 1; } );
BOOST_TEST( f2 );
BOOST_TEST_EQ( f2(), 1 );
BOOST_TEST_EQ( as_const_ref( f2 )(), 1 );
BOOST_TEST_EQ( std::move( f2 )(), 1 );
BOOST_TEST_EQ( std::move( as_const_ref( f2 ) )(), 1 );
}
{
auto l = []( int x ) { return x + 1; };
move_only_function<int( int )> f1( l );
BOOST_TEST( f1 );
BOOST_TEST_EQ( f1( 1 ), 2 );
move_only_function<int( int ) const> f2( l );
BOOST_TEST( f2 );
BOOST_TEST_EQ( f2( 1 ), 2 );
}
{
auto l = []( std::unique_ptr<int> x ) { return *x + 1; };
move_only_function<int( std::unique_ptr<int> )> f( std::move( l ) );
BOOST_TEST( f );
BOOST_TEST_EQ( f( make_unique<int>( 1 ) ), 2 );
}
{
auto p = make_unique<int>( 1 );
auto l = []( std::unique_ptr<int>& x ) { return *x + 1; };
move_only_function<int( std::unique_ptr<int>& )> f( l );
BOOST_TEST( f );
BOOST_TEST_EQ( f( p ), 2 );
}
{
int x = 1;
move_only_function<int( int )> f1( callable{} );
BOOST_TEST( f1 );
BOOST_TEST_EQ( f1( 1 ), 2);
BOOST_TEST_EQ( f1( x ), 2 );
int y = 2;
callable c;
move_only_function<int( int )> f2( std::move( c ) );
BOOST_TEST( f2 );
BOOST_TEST_EQ( f2( 2 ), 3 );
BOOST_TEST_EQ( f2( y ), 3 );
}
{
move_only_function<int( int, int )> f1( large_callable{} );
BOOST_TEST( f1 );
BOOST_TEST_EQ( f1( 1, 2 ), 3);
large_callable c;
move_only_function<int( int, int )> f2( std::move( c ) );
BOOST_TEST( f2 );
BOOST_TEST_EQ( f2( 1, 2 ), 3 );
}
{
move_only_function<int( int )> f1( in_place_type_t<callable>{}, make_unique<int>( 4321 ) );
BOOST_TEST_EQ( f1( 1234 ), 5555 );
move_only_function<int( int )> f2( in_place_type_t<large_callable>{}, make_unique<int>( 4321 ) );
BOOST_TEST_EQ( f2( 1234 ), 5555 );
move_only_function<int( int )> f3( in_place_type_t<int(*)( int )>{}, func2 );
BOOST_TEST_EQ( f3( 1233 ), 1234 );
move_only_function<int( int )> f4( in_place_type_t<int(*)( int )>{} );
BOOST_TEST( f4 != nullptr );
move_only_function<int( int )> f5( in_place_type_t<callable>{}, std::initializer_list<int>{ 1, 2, 3 }, 4, 5, 6 );
BOOST_TEST_EQ( f5( 7 ), 1 + 2 + 3 + 4 + 5 + 6 + 7 );
}
{
move_only_function<int()> f1( func1 );
move_only_function<int()> f2( std::move( f1 ) );
BOOST_TEST( !f1 );
BOOST_TEST( f2 );
BOOST_TEST_EQ( f2(), 1 );
}
{
move_only_function<int( int )> f1( callable{} );
move_only_function<int( int )> f2( std::move( f1 ) );
BOOST_TEST( !f1 );
BOOST_TEST( f2 );
BOOST_TEST_EQ( f2( 2 ), 3 );
}
{
move_only_function<int( int, int )> f1( large_callable{} );
move_only_function<int( int, int )> f2( std::move( f1 ) );
BOOST_TEST( !f1 );
BOOST_TEST( f2 );
BOOST_TEST_EQ( f2( 1, 2 ), 3 );
}
{
person p;
p.age_ = 35;
move_only_function<int( person& )> f1( &person::age_ );
BOOST_TEST_EQ( f1( p ), 35 );
p.age_ = 53;
move_only_function<int( person& )> f2( &person::age );
BOOST_TEST_EQ( f2( p ), 53 );
int person::*mp = nullptr;
move_only_function<int( person& )> f3( mp );
BOOST_TEST_NOT( f3 );
int (person::*mfp)() = nullptr;
move_only_function<int( person& )> f4( mfp );
BOOST_TEST_NOT( f4 );
}
{
struct tester
{
int operator()()
{
return 1;
}
int operator()() const
{
return 2;
}
};
tester t;
move_only_function<int()> f1( t );
move_only_function<int() const> f2( t );
BOOST_TEST_EQ( f1(), 1 );
BOOST_TEST_EQ( std::move( f1 )(), 1 );
BOOST_TEST_EQ( f2(), 2 );
BOOST_TEST_EQ( as_const_ref( f2 )(), 2 );
BOOST_TEST_EQ( std::move( as_const_ref( f2 ) )(), 2 );
}
{
struct tester
{
int operator()() noexcept
{
return 1;
}
int operator()() const noexcept
{
return 2;
}
};
tester t;
move_only_function<int() noexcept> f1( t );
move_only_function<int() const noexcept> f2( t );
BOOST_TEST_EQ( f1(), 1 );
BOOST_TEST_EQ( std::move( f1 )(), 1 );
BOOST_TEST_EQ( f2(), 2 );
BOOST_TEST_EQ( as_const_ref( f2 )(), 2 );
BOOST_TEST_EQ( std::move( as_const_ref( f2 ) )(), 2 );
}
{
struct tester
{
int operator()() &
{
return 1;
}
int operator()() &&
{
return 2;
}
int operator()() const&
{
return 3;
}
int operator()() const&&
{
return 4;
}
};
tester t;
move_only_function<int() &> f1( t );
move_only_function<int() &&> f2( t );
move_only_function<int() const&> f3( t );
BOOST_TEST_EQ( f1(), 1 );
BOOST_TEST_EQ( std::move( f2 )(), 2 );
BOOST_TEST_EQ( f3(), 3 );
BOOST_TEST_EQ( as_const_ref( f3 )(), 3 );
#if !BOOST_WORKAROUND(BOOST_GCC, < 40900)
move_only_function<int() const&&> f4( t );
BOOST_TEST_EQ( std::move( f4 )(), 4 );
BOOST_TEST_EQ( std::move( as_const_ref( f4 ) )(), 4 );
#endif
}
{
struct tester
{
int operator()() & noexcept
{
return 1;
}
int operator()() && noexcept
{
return 2;
}
int operator()() const& noexcept
{
return 3;
}
int operator()() const&& noexcept
{
return 4;
}
};
tester t;
move_only_function<int() &> f1( t );
move_only_function<int() &&> f2( t );
move_only_function<int() const&> f3( t );
BOOST_TEST_EQ( f1(), 1 );
BOOST_TEST_EQ( std::move( f2 )(), 2 );
BOOST_TEST_EQ( f3(), 3 );
BOOST_TEST_EQ( as_const_ref( f3 )(), 3 );
#if !BOOST_WORKAROUND(BOOST_GCC, < 40900)
move_only_function<int() const&&> f4( t );
BOOST_TEST_EQ( std::move( f4 )(), 4 );
BOOST_TEST_EQ( std::move( as_const_ref( f4 ) )(), 4 );
#endif
}
{
move_only_function<int( int )> f1( callable{} );
// f1 = std::move( f1 );
// BOOST_TEST_EQ( f1( 1233 ), 1234 );
move_only_function<int( int )> f2( large_callable{} );
f2 = std::move( f1 );
BOOST_TEST_EQ( f2( 1233 ), 1234 );
BOOST_TEST_NOT( f1 );
move_only_function<int( int )> f3( callable{} );
move_only_function<int( int )> f4( large_callable{} );
f3 = std::move( f4 );
BOOST_TEST_EQ( f3( 1233 ), 1234 );
BOOST_TEST_NOT( f4 );
move_only_function<int( int )> f5( callable{} );
f5 = nullptr;
BOOST_TEST_NOT( f5 );
move_only_function<int( int )> f6( large_callable{} );
f6 = nullptr;
BOOST_TEST_NOT( f6 );
move_only_function<int( int )> f7;
f7 = nullptr;
BOOST_TEST_NOT( f7 );
move_only_function<int( int )> f8( callable{} );
f8 = large_callable{};
BOOST_TEST_EQ( f8( 1233 ), 1234 );
move_only_function<int( int )> f9( large_callable{} );
f9 = callable{};
BOOST_TEST_EQ( f9( 1233 ), 1234 );
move_only_function<int( int )> f10;
f10 = callable{};
BOOST_TEST_EQ( f10( 1233 ), 1234 );
move_only_function<int( int )> f11;
f11 = large_callable{};
BOOST_TEST_EQ( f11( 1233 ), 1234 );
}
{
callable c1;
*c1.p_ = 1234;
large_callable c2;
*c2.p_ = 4321;
move_only_function<int( int )> f1( std::move( c1 ) );
move_only_function<int( int )> f2( std::move( c2 ) );
int x = 1;
BOOST_TEST_EQ( f1( x ), 1235 );
BOOST_TEST_EQ( f2( x ), 4322 );
swap( f1, f2 );
BOOST_TEST_EQ( f1( x ), 4322 );
BOOST_TEST_EQ( f2( x ), 1235 );
move_only_function<int( int )> f3( callable{} );
move_only_function<int( int )> f4;
swap( f3, f4 );
BOOST_TEST_NOT( f3 );
BOOST_TEST( f4 );
move_only_function<int( int )> f5;
move_only_function<int( int )> f6;
swap( f5, f6 );
BOOST_TEST_NOT( f5 );
BOOST_TEST_NOT( f6 );
}
{
struct throwing
{
static int x()
{
throw 1234;
}
int operator()()
{
throw 1234;
}
};
struct large_throwing
{
char padding[ 256 ] = {};
int operator()()
{
throw 1234;
}
};
move_only_function<int()> f1( &throwing::x );
move_only_function<int()> f2( throwing{} );
move_only_function<int()> f3( large_throwing{} );
BOOST_TEST_THROWS( f1(), int );
BOOST_TEST_THROWS( f2(), int );
BOOST_TEST_THROWS( f3(), int );
}
}
struct Q
{
void operator()() const &;
void operator()() &&;
};
struct R
{
void operator()() &;
void operator()() &&;
};
// These types are all small and nothrow move constructible
struct F { void operator()(); };
struct G { void operator()() const; };
struct H
{
H( int );
H( int, int ) noexcept;
void operator()() noexcept;
};
struct I
{
I( int, const char* );
I( std::initializer_list<char> );
int operator()() const noexcept;
};
static void test_traits()
{
// just copy the static assertions from libstdc++'s test suite, call.cc, cons.cc, conv.cc
// Check return types
BOOST_TEST_TRAIT_TRUE( ( is_same<void, invoke_result_t<move_only_function<void()>>> ) );
BOOST_TEST_TRAIT_TRUE( ( is_same<int, invoke_result_t<move_only_function<int()>>> ) );
BOOST_TEST_TRAIT_TRUE( ( is_same<int&, invoke_result_t<move_only_function<int&()>>> ) );
// With const qualifier
BOOST_TEST_TRAIT_FALSE( ( is_invocable< move_only_function<void()> const > ) );
BOOST_TEST_TRAIT_FALSE( ( is_invocable< move_only_function<void()> const &> ) );
BOOST_TEST_TRAIT_TRUE( ( is_invocable< move_only_function<void() const> > ) );
BOOST_TEST_TRAIT_TRUE( ( is_invocable< move_only_function<void() const> &> ) );
BOOST_TEST_TRAIT_TRUE( ( is_invocable< move_only_function<void() const> const > ) );
BOOST_TEST_TRAIT_TRUE( ( is_invocable< move_only_function<void() const> const &> ) );
// With no ref-qualifier
BOOST_TEST_TRAIT_TRUE( ( is_invocable< move_only_function<void()> > ) );
BOOST_TEST_TRAIT_TRUE( ( is_invocable< move_only_function<void()> &> ) );
BOOST_TEST_TRAIT_TRUE( ( is_invocable< move_only_function<void() const> > ) );
BOOST_TEST_TRAIT_TRUE( ( is_invocable< move_only_function<void() const> &> ) );
BOOST_TEST_TRAIT_TRUE( ( is_invocable< move_only_function<void() const> const > ) );
BOOST_TEST_TRAIT_TRUE( ( is_invocable< move_only_function<void() const> const &> ) );
// With & ref-qualifier
BOOST_TEST_TRAIT_FALSE( ( is_invocable< move_only_function<void()&> > ) );
BOOST_TEST_TRAIT_TRUE( ( is_invocable< move_only_function<void()&> &> ) );
BOOST_TEST_TRAIT_TRUE( ( is_invocable< move_only_function<void() const&> > ) );
BOOST_TEST_TRAIT_TRUE( ( is_invocable< move_only_function<void() const&> &> ) );
BOOST_TEST_TRAIT_TRUE( ( is_invocable< move_only_function<void() const&> const > ) );
BOOST_TEST_TRAIT_TRUE( ( is_invocable< move_only_function<void() const&> const &> ) );
// With && ref-qualifier
BOOST_TEST_TRAIT_TRUE( ( is_invocable< move_only_function<void()&&> > ) );
BOOST_TEST_TRAIT_FALSE( ( is_invocable< move_only_function<void()&&> &> ) );
BOOST_TEST_TRAIT_TRUE( ( is_invocable< move_only_function<void() const&&> > ) );
BOOST_TEST_TRAIT_FALSE( ( is_invocable< move_only_function<void() const&&> &> ) );
BOOST_TEST_TRAIT_TRUE( ( is_invocable< move_only_function<void() const&&> const > ) );
BOOST_TEST_TRAIT_FALSE( ( is_invocable< move_only_function<void() const&&> const &> ) );
#if defined(__cpp_noexcept_function_type)
// With noexcept-specifier
BOOST_TEST_TRAIT_FALSE( ( is_nothrow_invocable< move_only_function<void()> > ) );
BOOST_TEST_TRAIT_FALSE( ( is_nothrow_invocable< move_only_function<void() noexcept(false)> > ) );
BOOST_TEST_TRAIT_TRUE( ( is_nothrow_invocable< move_only_function<void() noexcept> > ) );
BOOST_TEST_TRAIT_TRUE( ( is_nothrow_invocable< move_only_function<void()& noexcept>& > ) );
#endif
BOOST_TEST_TRAIT_TRUE( ( std::is_nothrow_default_constructible<move_only_function<void()>> ) );
BOOST_TEST_TRAIT_TRUE( ( is_nothrow_constructible<move_only_function<void()>, std::nullptr_t> ) );
BOOST_TEST_TRAIT_TRUE( ( std::is_nothrow_move_constructible<move_only_function<void()>> ) );
BOOST_TEST_TRAIT_FALSE( ( std::is_copy_constructible<move_only_function<void()>> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void()>, void()> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void()>, void( & )()> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void()>, void( * )()> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void()>, int()> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void()>, int( & )()> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void()>, int( * )()> ) );
BOOST_TEST_TRAIT_FALSE( ( is_constructible<move_only_function<void()>, void( int )> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void(int)>, void( int )> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void( int )>, in_place_type_t<void(*)( int )>, void( int )> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void()>, void() noexcept> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void() noexcept>, void() noexcept> ) );
#if defined(__cpp_noexcept_function_type)
BOOST_TEST_TRAIT_FALSE( ( is_constructible<move_only_function<void() noexcept>, void()> ) );
#endif
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void()>, Q> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void() const>, Q> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void() &>, Q> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void() const &>, Q> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void() &&>, Q> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void() const &&>, Q> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void()>, R> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void()&>, R> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void()&&>, R> ) );
BOOST_TEST_TRAIT_FALSE( ( is_constructible<move_only_function<void() const>, R> ) );
BOOST_TEST_TRAIT_FALSE( ( is_constructible<move_only_function<void() const&>, R> ) );
BOOST_TEST_TRAIT_FALSE( ( is_constructible<move_only_function<void() const&&>, R> ) );
BOOST_TEST_TRAIT_TRUE( ( is_nothrow_constructible<move_only_function<void()>, F> ) );
BOOST_TEST_TRAIT_TRUE( ( is_nothrow_constructible<move_only_function<void()>, G> ) );
BOOST_TEST_TRAIT_TRUE( ( is_nothrow_constructible<move_only_function<void() const>, G> ) );
BOOST_TEST_TRAIT_TRUE( ( is_nothrow_constructible<move_only_function<void()>, H> ) );
BOOST_TEST_TRAIT_TRUE( ( is_nothrow_constructible<move_only_function<void() noexcept>, H> ) );
BOOST_TEST_TRAIT_FALSE( ( is_nothrow_constructible<move_only_function<void() noexcept >, in_place_type_t<H>, int> ) );
BOOST_TEST_TRAIT_TRUE( ( is_nothrow_constructible<move_only_function<void() noexcept>, in_place_type_t<H>, int, int> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void()>, in_place_type_t<I>, int, const char*> ) );
BOOST_TEST_TRAIT_TRUE( ( is_constructible<move_only_function<void()>, in_place_type_t<I>, std::initializer_list<char>> ) );
BOOST_TEST_TRAIT_FALSE( ( is_constructible<move_only_function<void()>, move_only_function<void() &>> ) );
BOOST_TEST_TRAIT_FALSE( ( is_constructible<move_only_function<void()>, move_only_function<void() &&>> ) );
BOOST_TEST_TRAIT_FALSE( ( is_constructible<move_only_function<void()&>, move_only_function<void() &&>> ) );
BOOST_TEST_TRAIT_FALSE( ( is_constructible<move_only_function<void() const>, move_only_function<void()>> ) );
using FuncType = int( int );
// Top level const qualifiers are ignored in function types, and decay
// is performed.
BOOST_TEST_TRAIT_TRUE( ( is_same<move_only_function<void( int const )>, move_only_function<void( int )>> ) );
BOOST_TEST_TRAIT_TRUE( ( is_same<move_only_function<void( int[ 2 ] )>, move_only_function<void( int* )>> ) );
BOOST_TEST_TRAIT_TRUE( ( is_same<move_only_function<void( int[] )>, move_only_function<void( int* )>> ) );
BOOST_TEST_TRAIT_TRUE( ( is_same<move_only_function<void(int const[ 5 ])>, move_only_function<void( int const* )>> ) );
BOOST_TEST_TRAIT_TRUE( ( is_same<move_only_function<void( FuncType )>, move_only_function<void( FuncType* )>> ) );
}
static void test_conv()
{
{
noex_callable nt;
move_only_function<int( int ) noexcept> f1( std::move( nt ) );
move_only_function<int( int )> f2( std::move( f1 ) );
BOOST_TEST_EQ( f2( 1234 ), 1235 );
}
{
auto l = []( noex_callable const& c ) noexcept { return *c.p_ + 1234; };
noex_callable c;
move_only_function<int( noex_callable ) const noexcept> f1( l );
BOOST_TEST_EQ( f1( c ), 1235 );
move_only_function<int( noex_callable ) const> f2( std::move( f1 ) );
BOOST_TEST_EQ( f2( c ), 1235 );
move_only_function<int( noex_callable )> f3( std::move( f2 ) );
BOOST_TEST_EQ( f3( c ), 1235 );
move_only_function<int( noex_callable&& )> f4( std::move( f3 ) );
BOOST_TEST_EQ( f4( noex_callable{} ), 1235 );
move_only_function<int( noex_callable&& ) &&> f5( std::move( f4 ) );
BOOST_TEST_EQ( std::move( f5 )( noex_callable{} ), 1235 );
move_only_function<int( noex_callable&& )> f6( l );
move_only_function<int( noex_callable&& ) &> f7( std::move( f6 ) );
BOOST_TEST_EQ( f7( noex_callable{} ), 1235 );
// TODO: libstdc++ includes this test case but it seems like pedantically calling a `long(*)(Arg)` should
// be UB in the general sense. We need to confirm one way or another if this is something we need to support.
//
// move_only_function<int( noex_callable ) const noexcept> f8( l );
// move_only_function<long( noex_callable ) const noexcept> f9( std::move( f8 ) );
// BOOST_TEST_EQ( f9( noex_callable{} ), 1235 );
}
{
move_only_function<int( long ) const noexcept> e;
BOOST_TEST( e == nullptr );
move_only_function<int( long ) const> e2( std::move( e ) );
BOOST_TEST( e2 == nullptr );
e2 = std::move( e );
BOOST_TEST( e2 == nullptr );
move_only_function<int( long )> e3( std::move( e2 ) );
BOOST_TEST( e3 == nullptr );
}
}
int main()
{
test_call();
test_traits();
test_conv();
return boost::report_errors();
}

33
test/nontype_test.cpp Normal file
View File

@@ -0,0 +1,33 @@
// Copyright 2025 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/detail/nontype.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/config/pragma_message.hpp>
#if !( defined(__cpp_nontype_template_parameter_auto) && __cpp_nontype_template_parameter_auto >= 201606L )
BOOST_PRAGMA_MESSAGE("Test skipped, __cpp_nontype_template_parameter_auto is not defined to at least 201606L")
int main() {}
#else
void f() {}
struct X
{
void f() {}
};
int main()
{
BOOST_TEST_TRAIT_SAME( boost::compat::nontype_t< 5 > const, decltype( boost::compat::nontype< 5 > ) );
BOOST_TEST_TRAIT_SAME( boost::compat::nontype_t< ::f > const, decltype( boost::compat::nontype< ::f > ) );
BOOST_TEST_TRAIT_SAME( boost::compat::nontype_t< &X::f > const, decltype( boost::compat::nontype< &X::f > ) );
return boost::report_errors();
}
#endif

View File

@@ -3,6 +3,10 @@
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/latch.hpp>
#include <boost/compat/shared_lock.hpp>
#include <boost/compat/invoke.hpp>
#include <boost/compat/bind_front.hpp>
#include <boost/compat/bind_back.hpp>
int main()
{

View File

@@ -1,3 +1,9 @@
// Copyright 2023 Peter Dimov.
// Copyright 2023 Christian Mazakas.
// Copyright 2023 Ed Catmur
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#ifdef _MSC_VER
#pragma warning(disable: 4530) // C++ exception handler used, but unwing semantics not enabled
#pragma warning(disable: 4577) // noexcept used with no exception handling mode specified

View File

@@ -0,0 +1,60 @@
// Copyright 2024 Ruben Perez Hidalgo.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/to_array.hpp>
#include <boost/core/lightweight_test.hpp>
#include <array>
#include <vector>
namespace compat = boost::compat;
int main()
{
{
// regular C array
int input[] = {1, 2};
auto output = compat::to_array(input);
static_assert(std::is_same<decltype(output), std::array<int, 2>>::value, "");
BOOST_TEST_EQ(output[0], 1);
BOOST_TEST_EQ(output[1], 2);
}
{
// regular C array, const
const int input[] = {1, 2};
auto output = compat::to_array(input);
static_assert(std::is_same<decltype(output), std::array<int, 2>>::value, "");
BOOST_TEST_EQ(output[0], 1);
BOOST_TEST_EQ(output[1], 2);
}
{
// values not moved
const std::vector<int> vec{1, 2};
std::vector<int> input[]{vec};
auto output = compat::to_array(input);
static_assert(std::is_same<decltype(output), std::array<std::vector<int>, 1>>::value, "");
BOOST_TEST_ALL_EQ(output[0].begin(), output[0].end(), vec.begin(), vec.end());
BOOST_TEST_ALL_EQ(input[0].begin(), input[0].end(), vec.begin(), vec.end()); // input not modified
}
{
// const values work
const std::vector<int> vec{1, 2};
const std::vector<int> input[]{vec};
auto output = compat::to_array(input);
static_assert(std::is_same<decltype(output), std::array<std::vector<int>, 1>>::value, "");
BOOST_TEST_ALL_EQ(output[0].begin(), output[0].end(), vec.begin(), vec.end());
BOOST_TEST_ALL_EQ(input[0].begin(), input[0].end(), vec.begin(), vec.end()); // input not modified
}
{
// constexpr check
constexpr int input[] = {1, 2, 3};
constexpr auto output = compat::to_array(input);
static_assert(std::is_same<decltype(output), const std::array<int, 3>>::value, "");
BOOST_TEST_EQ(output[0], 1);
BOOST_TEST_EQ(output[1], 2);
BOOST_TEST_EQ(output[2], 3);
}
return boost::report_errors();
}

Some files were not shown because too many files have changed in this diff Show More