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

34 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
22 changed files with 3708 additions and 278 deletions

View File

@@ -34,7 +34,6 @@ local linux_pipeline(name, image, environment, packages = "", sources = [], arch
'set -e',
'uname -a',
'echo $DRONE_STAGE_MACHINE',
'wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -',
] +
(if sources != [] then [ ('apt-add-repository "' + source + '"') for source in sources ] else []) +
(if packages != "" then [ 'apt-get update', 'apt-get -y install ' + packages ] else []) +
@@ -153,38 +152,31 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
),
linux_pipeline(
"Linux 23.04 GCC 13 32/64",
"cppalliance/droneubuntu2304:1",
"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 ASAN",
"Linux 24.04 GCC 14 32/64 ASAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b', ADDRMD: '32' } + asan,
{ 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 64 ASAN",
"Linux 24.04 GCC 14 32/64 UBSAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b', ADDRMD: '64' } + asan,
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b', ADDRMD: '32,64' } + ubsan,
"g++-14-multilib",
),
linux_pipeline(
"Linux 24.04 GCC 14 32 UBSAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b', ADDRMD: '32' } + ubsan,
"g++-14-multilib",
),
linux_pipeline(
"Linux 24.04 GCC 14 64 UBSAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '11,14,17,20,2b', ADDRMD: '64' } + ubsan,
"g++-14-multilib",
"Linux 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(
@@ -195,38 +187,52 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
),
linux_pipeline(
"Linux 23.04 Clang 16",
"cppalliance/droneubuntu2304:1",
"Linux 24.04 Clang 16",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-16', CXXSTD: '11,14,17,20,2b' },
"clang-16",
),
linux_pipeline(
"Linux 23.10 Clang 17 UBSAN",
"cppalliance/droneubuntu2310:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '11,14,17,20,2b' } + ubsan,
"Linux 24.04 Clang 17",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '11,14,17,20,2b' },
"clang-17",
),
linux_pipeline(
"Linux 23.10 Clang 17 ASAN",
"cppalliance/droneubuntu2310:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '11,14,17,20,2b' } + asan,
"clang-17",
),
linux_pipeline(
"Linux 24.04 Clang 18 UBSAN",
"Linux 24.04 Clang 18",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '11,14,17,20,2b' } + ubsan,
{ TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '11,14,17,20,2b' },
"clang-18",
),
linux_pipeline(
"Linux 24.04 Clang 18 ASAN",
"Linux 24.04 Clang 19",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '11,14,17,20,2b' } + asan,
"clang-18",
{ 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(
@@ -251,6 +257,18 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
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",

View File

@@ -39,18 +39,22 @@ jobs:
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"
@@ -61,7 +65,7 @@ jobs:
install: g++-12
- toolset: gcc-13
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:23.04
container: ubuntu:24.04
os: ubuntu-latest
install: g++-13
- toolset: gcc-14
@@ -69,6 +73,11 @@ jobs:
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"
@@ -90,37 +99,44 @@ jobs:
- 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
@@ -143,13 +159,13 @@ jobs:
- toolset: clang
compiler: clang++-16
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:23.04
container: ubuntu:24.04
os: ubuntu-latest
install: clang-16
- toolset: clang
compiler: clang++-17
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:23.10
container: ubuntu:24.04
os: ubuntu-latest
install: clang-17
- toolset: clang
@@ -159,34 +175,60 @@ jobs:
os: ubuntu-latest
install: clang-18
- toolset: clang
compiler: clang++-19
cxxstd: "03,11,14,17,20,2b"
os: macos-12
container: ubuntu:24.04
os: ubuntu-latest
install: clang-19
- toolset: clang
cxxstd: "03,11,14,17,20,2b"
os: macos-13
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-14
- toolset: clang
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:
- name: Enable Node 16
run: |
echo "ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true" >> $GITHUB_ENV
- 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
@@ -232,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
@@ -251,7 +285,7 @@ jobs:
- toolset: gcc
cxxstd: "03,11,14,17,2a"
addrmd: 64
os: windows-2019
os: windows-2022
runs-on: ${{matrix.os}}
@@ -291,11 +325,11 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-12
- os: macos-13
- os: ubuntu-24.04
- os: macos-14
- os: macos-15
- os: macos-26
runs-on: ${{matrix.os}}
@@ -340,11 +374,11 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-12
- os: macos-13
- os: ubuntu-24.04
- os: macos-14
- os: macos-15
- os: macos-26
runs-on: ${{matrix.os}}
@@ -399,11 +433,11 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-20.04
- os: ubuntu-22.04
- os: macos-12
- os: macos-13
- os: ubuntu-24.04
- os: macos-14
- os: macos-15
- os: macos-26
runs-on: ${{matrix.os}}
@@ -456,8 +490,7 @@ jobs:
fail-fast: false
matrix:
include:
- os: windows-2019
- os: windows-2022
- os: windows-latest
runs-on: ${{matrix.os}}
@@ -505,8 +538,7 @@ jobs:
fail-fast: false
matrix:
include:
- os: windows-2019
- os: windows-2022
- os: windows-latest
runs-on: ${{matrix.os}}
@@ -572,8 +604,7 @@ jobs:
fail-fast: false
matrix:
include:
- os: windows-2019
- os: windows-2022
- os: windows-latest
runs-on: ${{matrix.os}}

View File

@@ -8,6 +8,14 @@ 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.)

View File

@@ -18,6 +18,8 @@ The header `<boost/compat/function_ref.hpp>` implements the {cpp}26 class
`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
@@ -48,19 +50,22 @@ 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)> {
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;
template<class F> function_ref(F*) noexcept;
template<class F> function_ref(F&&) noexcept;
R operator()(ArgTypes...) const noexcept(noex);
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
@@ -93,7 +98,7 @@ template<class F> function_ref(F&& fn) noexcept;
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...)`.
Calling the `function_ref` is expression-equivalent to `invoke_r<R>(static_cast<cv T&>(f), call-args...)`.
### Pointer to Member Function Constructor
@@ -105,7 +110,7 @@ template<auto f> function_ref(nontype_t<f>) noexcept;
Effects:;; Constructs a `function_ref` using the supplied pointer to member function. This overload only participates
in resolution when `f` is a pointer to member or pointer to member function. +
+
Calling the `function_ref` is express-equivalent to: `invoke_r<R>(f, class-args)`.
Calling the `function_ref` is expression-equivalent to `invoke_r<R>(f, call-args)`.
Example:;;
+
--
@@ -113,7 +118,7 @@ Example:;;
struct point { int x = 1, y = 2; };
point p;
compat::function_ref<int(point const&)> f(compat::nontype_t<&point::x>{});
compat::function_ref<int(point const&)> f(compat::nontype<&point::x>);
BOOST_TEST_EQ(f(p), 1);
```
@@ -137,7 +142,7 @@ Example:;;
struct point { int x = 1, y = 2; };
point p;
compat::function_ref<int()> f(compat::nontype_t<&point::x>{}, p);
compat::function_ref<int()> f(compat::nontype<&point::x>, p);
BOOST_TEST_EQ(f(), 1);
```
@@ -159,7 +164,7 @@ Example:;;
struct point { int x = 1, y = 2; };
point p;
compat::function_ref<int()> f(compat::nontype_t<&point::x>{}, &p);
compat::function_ref<int()> f(compat::nontype<&point::x>, &p);
BOOST_TEST_EQ(f(), 1);
```

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
```

View File

@@ -11,6 +11,8 @@ 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

@@ -61,7 +61,7 @@ Type requirements:;; `std::is_constructible_v<remove_cv_t<T>, T&> && !std::is_ar
```cpp
template <class T, std::size_t N>
constexpr std::array<remove_cvref_t<T>, N> to_array(T (&a)[N]);
constexpr std::array<remove_cv_t<T>, N> to_array(T (&a)[N]);
```
[horizontal]

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,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

@@ -5,31 +5,19 @@
// 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>
#if defined(__cpp_nontype_template_parameter_auto) && __cpp_nontype_template_parameter_auto >= 201606L
#define BOOST_COMPAT_HAS_AUTO_NTTP
#endif
namespace boost {
namespace compat {
template <class... S>
struct function_ref;
#if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
template <auto V>
struct nontype_t {
explicit nontype_t() = default;
};
#endif
namespace detail {
template <bool NoEx>
@@ -55,16 +43,14 @@ struct invoke_object_holder {
}
};
#if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
template <auto f, bool Const, bool NoEx, class R, class... 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 <auto f, class U, bool Const, bool NoEx, class R, class... 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>;
@@ -73,7 +59,7 @@ struct invoke_target_mem_fn_holder {
}
};
template <auto f, class T, bool Const, bool NoEx, class R, class... 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>;
@@ -81,8 +67,6 @@ struct invoke_ptr_mem_fn_holder {
}
};
#endif
template <bool Const, bool NoEx, class R, class... Args>
struct function_ref_base {
private:
@@ -106,32 +90,28 @@ public:
thunk_.pobj_ = const_cast<void*>(static_cast<void const*>(std::addressof(fn)));
}
#if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
template <auto f, class F = decltype(f)>
function_ref_base(mem_fn_tag, nontype_t<f>)
: thunk_{}, invoke_(&invoke_mem_fn_holder<F{f}, Const, NoEx, R, Args...>::invoke_mem_fn) {
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 <auto f, class U, class F = decltype(f)>
function_ref_base(mem_fn_tag, nontype_t<f>, U&& obj)
: thunk_{}, invoke_(&invoke_target_mem_fn_holder<F{f}, U, Const, NoEx, R, Args...>::invoke_mem_fn) {
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 <auto f, class T, class F = decltype(f)>
function_ref_base(mem_fn_tag, nontype_t<f>, T* obj)
: thunk_{}, invoke_(&invoke_ptr_mem_fn_holder<F{f}, T, Const, NoEx, R, Args...>::invoke_mem_fn) {
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));
}
#endif
function_ref_base(const function_ref_base&) noexcept = default;
function_ref_base& operator=(const function_ref_base&) noexcept = default;
R operator()(Args&&... args) const noexcept(NoEx) { return this->invoke_(thunk_, std::forward<Args>(args)...); }
R operator()(Args... args) const noexcept(NoEx) { return this->invoke_(thunk_, std::forward<Args>(args)...); }
};
} // namespace detail
@@ -157,19 +137,15 @@ public:
int> = 0>
function_ref(F&& fn) noexcept : base_type(obj_tag{}, fn) {}
#if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
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 <auto f, class F = decltype(f), enable_if_t<is_invocable_using<F>::value, int> = 0>
function_ref(nontype_t<f> x) noexcept : base_type(mem_fn_tag{}, x) {}
template <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 <auto f, class U, class T = remove_reference_t<U>, class F = decltype(f),
enable_if_t<!std::is_rvalue_reference_v<U&&> && is_invocable_using<F, T&>::value, int> = 0>
function_ref(nontype_t<f> x, U&& obj) noexcept : base_type(mem_fn_tag{}, x, std::forward<U>(obj)) {}
template <auto f, class T, class F = decltype(f), enable_if_t<is_invocable_using<F, T*>::value, int> = 0>
function_ref(nontype_t<f> x, T* obj) noexcept : base_type(mem_fn_tag{}, x, obj) {}
#endif
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;
@@ -199,19 +175,15 @@ public:
int> = 0>
function_ref(F&& fn) noexcept : base_type(obj_tag{}, fn) {}
#if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
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 <auto f, class F = decltype(f), enable_if_t<is_invocable_using<F>::value, int> = 0>
function_ref(nontype_t<f> x) noexcept : base_type(mem_fn_tag{}, x) {}
template <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 <auto f, class U, class T = remove_reference_t<U>, class F = decltype(f),
enable_if_t<!std::is_rvalue_reference_v<U&&> && is_invocable_using<F, T const&>::value, int> = 0>
function_ref(nontype_t<f> x, U&& obj) noexcept : base_type(mem_fn_tag{}, x, std::forward<U>(obj)) {}
template <auto f, class T, class F = decltype(f), enable_if_t<is_invocable_using<F, T const*>::value, int> = 0>
function_ref(nontype_t<f> x, T const* obj) noexcept : base_type(mem_fn_tag{}, x, obj) {}
#endif
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;
@@ -243,19 +215,15 @@ public:
int> = 0>
function_ref(F&& fn) noexcept : base_type(obj_tag{}, fn) {}
#if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
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 <auto f, class F = decltype(f), enable_if_t<is_invocable_using<F>::value, int> = 0>
function_ref(nontype_t<f> x) noexcept : base_type(mem_fn_tag{}, x) {}
template <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 <auto f, class U, class T = remove_reference_t<U>, class F = decltype(f),
enable_if_t<!std::is_rvalue_reference_v<U&&> && is_invocable_using<F, T&>::value, int> = 0>
function_ref(nontype_t<f> x, U&& obj) noexcept : base_type(mem_fn_tag{}, x, std::forward<U>(obj)) {}
template <auto f, class T, class F = decltype(f), enable_if_t<is_invocable_using<F, T*>::value, int> = 0>
function_ref(nontype_t<f> x, T* obj) noexcept : base_type(mem_fn_tag{}, x, obj) {}
#endif
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;
@@ -285,19 +253,15 @@ public:
int> = 0>
function_ref(F&& fn) noexcept : base_type(obj_tag{}, fn) {}
#if defined(BOOST_COMPAT_HAS_AUTO_NTTP)
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 <auto f, class F = decltype(f), enable_if_t<is_invocable_using<F>::value, int> = 0>
function_ref(nontype_t<f> x) noexcept : base_type(mem_fn_tag{}, x) {}
template <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 <auto f, class U, class T = remove_reference_t<U>, class F = decltype(f),
enable_if_t<!std::is_rvalue_reference_v<U&&> && is_invocable_using<F, T const&>::value, int> = 0>
function_ref(nontype_t<f> x, U&& obj) noexcept : base_type(mem_fn_tag{}, x, std::forward<U>(obj)) {}
template <auto f, class T, class F = decltype(f), enable_if_t<is_invocable_using<F, T const*>::value, int> = 0>
function_ref(nontype_t<f> x, T const* obj) noexcept : base_type(mem_fn_tag{}, x, obj) {}
#endif
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;

File diff suppressed because it is too large Load Diff

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

@@ -2,7 +2,7 @@
#define BOOST_COMPAT_TYPE_TRAITS_HPP_INCLUDED
// Copyright 2024 Peter Dimov
// Copyright 2024 Christian Mazakas
// Copyright 2024-2025 Christian Mazakas
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
@@ -11,10 +11,14 @@
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;
@@ -35,6 +39,11 @@ 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

View File

@@ -113,5 +113,11 @@ 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

@@ -98,8 +98,9 @@ int main() {
// f1
{
int x = 1;
compat::function_ref<int(int)> fv1(f1);
BOOST_TEST_EQ(fv1(1), 1);
BOOST_TEST_EQ(fv1(x), 1);
compat::function_ref<int(int) const> fv2(f1);
BOOST_TEST_EQ(fv2(1), 1);

View File

@@ -7,19 +7,23 @@
#endif
#include <boost/compat/function_ref.hpp>
#if !defined(BOOST_COMPAT_HAS_AUTO_NTTP)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("no support for placeholder NTTPs detected, skipping this test")
int main() {}
#else
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <memory>
#include <type_traits>
#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_;
@@ -35,130 +39,148 @@ 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>, compat::nontype_t<&F1::m1>>));
(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>, compat::nontype_t<&F1::m2>>));
(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>, compat::nontype_t<&F1::m3>>));
(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>, compat::nontype_t<&F1::m4>>));
(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(compat::nontype_t<&F1::m2>{});
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(compat::nontype_t<&F1::m4>{});
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>, compat::nontype_t<&F1::m1>>));
(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>, compat::nontype_t<&F1::m3>>));
(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(compat::nontype_t<&F1::m2>{});
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(compat::nontype_t<&F1::m4>{});
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>, compat::nontype_t<&F1::m1>>));
(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>, compat::nontype_t<&F1::m2>>));
(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>, compat::nontype_t<&F1::m3>>));
(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(compat::nontype_t<&F1::m4>{});
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>, compat::nontype_t<&F1::m1>, F1&>));
(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>, compat::nontype_t<&F1::m2>, F1&>));
(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>, compat::nontype_t<&F1::m3>, F1&>));
(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>, compat::nontype_t<&F1::m4>, F1&>));
(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(compat::nontype_t<&F1::m2>{}, 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(compat::nontype_t<&F1::m4>{}, f1);
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>, compat::nontype_t<&F1::m1>, F1 const&>));
(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>, compat::nontype_t<&F1::m2>, F1 const&>));
(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>,
compat::nontype_t<&F1::m3>, F1 const&>));
NONTYPE_T(&F1::m3), F1 const&>));
#endif
F1 f1;
compat::function_ref<int(int, int, int) const noexcept> fn4(compat::nontype_t<&F1::m4>{}, 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(compat::nontype_t<&F1::m4>{}, f1_2);
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>, compat::nontype_t<&F1::m1>, F1*>));
(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>, compat::nontype_t<&F1::m2>, F1*>));
(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>, compat::nontype_t<&F1::m3>, F1*>));
(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>, compat::nontype_t<&F1::m4>, F1*>));
(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(compat::nontype_t<&F1::m2>{}, &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(compat::nontype_t<&F1::m4>{}, &f1);
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>, compat::nontype_t<&F1::m1>, F1 const*>));
(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>, compat::nontype_t<&F1::m2>, F1 const*>));
(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>,
compat::nontype_t<&F1::m3>, F1 const*>));
NONTYPE_T(&F1::m3), F1 const*>));
#endif
F1 const f1;
compat::function_ref<int(int, int, int) const noexcept> fn4(compat::nontype_t<&F1::m4>{}, &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(compat::nontype_t<&F1::m4>{}, &f1_2);
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();
}
#endif

View File

@@ -7,19 +7,23 @@
#endif
#include <boost/compat/function_ref.hpp>
#if !defined(BOOST_COMPAT_HAS_AUTO_NTTP)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("no support for placeholder NTTPs detected, skipping this test")
int main() {}
#else
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <memory>
#include <type_traits>
#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;
@@ -38,120 +42,121 @@ int main() {
{
F1 f1;
compat::function_ref<int(F1&)> fn1(compat::nontype_t<&F1::m1>{});
compat::function_ref<int(F1&)> fn1(NONTYPE(&F1::m1));
BOOST_TEST_EQ(fn1(f1), 0);
compat::function_ref<int(F1&, int)> fn2(compat::nontype_t<&F1::m2>{});
BOOST_TEST_EQ(fn2(f1, 2), 12);
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(compat::nontype_t<&F1::m3>{});
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(compat::nontype_t<&F1::m4>{});
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(compat::nontype_t<&F1::q_>{});
compat::function_ref<int(F1&)> a1(NONTYPE(&F1::q_));
BOOST_TEST_EQ(a1(f1), 1337);
}
{
F1 f1;
compat::function_ref<int(F1&) const> fn1(compat::nontype_t<&F1::m1>{});
compat::function_ref<int(F1&) const> fn1(NONTYPE(&F1::m1));
BOOST_TEST_EQ(fn1(f1), 0);
compat::function_ref<int(F1&, int) const> fn2(compat::nontype_t<&F1::m2>{});
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(compat::nontype_t<&F1::m3>{});
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(compat::nontype_t<&F1::m4>{});
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&)>, compat::nontype_t<&F1::m1>>));
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)>, compat::nontype_t<&F1::m2>>));
(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(compat::nontype_t<&F1::m3>{});
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(compat::nontype_t<&F1::m4>{});
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(compat::nontype_t<&F1::m3>{});
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(compat::nontype_t<&F1::m4>{});
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)>, compat::nontype_t<&F1::m2>, F1&>));
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)>, compat::nontype_t<&F1::m2>, F1 const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<int(int)>, compat::nontype_t<&F1::m2>, F1&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<int(int)>, compat::nontype_t<&F1::m2>, F1>));
(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>, compat::nontype_t<&F1::m3>, F1&>));
(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>, compat::nontype_t<&F1::m3>, F1 const&>));
(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>, compat::nontype_t<&F1::m3>, F1&&>));
(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>, compat::nontype_t<&F1::m3>, F1>));
(std::is_constructible<compat::function_ref<int(int, int) const>, NONTYPE_T(&F1::m3), F1>));
}
{
F1 f1;
compat::function_ref<int()> fn1(compat::nontype_t<&F1::m1>{}, f1);
compat::function_ref<int()> fn1(NONTYPE(&F1::m1), f1);
BOOST_TEST_EQ(fn1(), 0);
compat::function_ref<int(int)> fn2(compat::nontype_t<&F1::m2>{}, f1);
compat::function_ref<int(int)> fn2(NONTYPE(&F1::m2), f1);
BOOST_TEST_EQ(fn2(2), 12);
compat::function_ref<int(int, int)> fn3(compat::nontype_t<&F1::m3>{}, f1);
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(compat::nontype_t<&F1::m4>{}, f1);
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>, compat::nontype_t<&F1::m1>, 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>, compat::nontype_t<&F1::m2>, F1&>));
(std::is_constructible<compat::function_ref<int(int) const>, NONTYPE_T(&F1::m2), F1&>));
compat::function_ref<int(int, int) const> fn3(compat::nontype_t<&F1::m3>{}, 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(compat::nontype_t<&F1::m4>{}, f1);
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(compat::nontype_t<&F1::m1>{}, &f1);
compat::function_ref<int()> fn1(NONTYPE(&F1::m1), &f1);
BOOST_TEST_EQ(fn1(), 0);
compat::function_ref<int(int)> fn2(compat::nontype_t<&F1::m2>{}, &f1);
compat::function_ref<int(int)> fn2(NONTYPE(&F1::m2), &f1);
BOOST_TEST_EQ(fn2(2), 12);
compat::function_ref<int(int, int)> fn3(compat::nontype_t<&F1::m3>{}, &f1);
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(compat::nontype_t<&F1::m4>{}, &f1);
compat::function_ref<int(int, int, int)> fn4(NONTYPE(&F1::m4), &f1);
BOOST_TEST_EQ(fn4(2, 3, 4), 1234);
}
@@ -159,18 +164,16 @@ int main() {
F1 const f1;
BOOST_TEST_TRAIT_FALSE(
(std::is_constructible<compat::function_ref<int() const>, compat::nontype_t<&F1::m1>, F1 const*>));
(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>, compat::nontype_t<&F1::m2>, F1 const*>));
(std::is_constructible<compat::function_ref<int(int) const>, NONTYPE_T(&F1::m2), F1 const*>));
compat::function_ref<int(int, int) const> fn3(compat::nontype_t<&F1::m3>{}, &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(compat::nontype_t<&F1::m4>{}, &f1);
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();
}
#endif

View File

@@ -65,8 +65,8 @@ int main() {
BOOST_TEST_TRAIT_FALSE((std::is_constructible<compat::function_ref<S1>, F1 const&&>));
compat::function_ref<S2> fv2(f);
BOOST_TEST_EQ(fv2(1), 1);
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&>));

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

@@ -0,0 +1,75 @@
// Copyright 2025 Braden Ganetsky
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/compat/to_underlying.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <cstdint>
enum unscoped
{
unscoped_value = 1
};
enum unscoped_int8_t : std::int8_t
{
unscoped_int8_t_value = 2
};
enum unscoped_uint16_t : std::uint16_t
{
unscoped_uint16_t_value = 3
};
enum class scoped
{
value = 4
};
enum class scoped_int8_t : std::int8_t
{
value = 5
};
enum class scoped_uint16_t : std::uint16_t
{
value = 6
};
int main()
{
{
auto output = boost::compat::to_underlying(unscoped_value);
// Per the standard [dcl.enum], the underlying type of an unscoped enumeration
// is unspecified, unless it is explicitly specified.
BOOST_TEST_EQ(output, 1);
}
{
auto output = boost::compat::to_underlying(unscoped_int8_t_value);
BOOST_TEST_TRAIT_SAME(decltype(output), std::int8_t);
BOOST_TEST_EQ(output, 2);
}
{
auto output = boost::compat::to_underlying(unscoped_uint16_t_value);
BOOST_TEST_TRAIT_SAME(decltype(output), std::uint16_t);
BOOST_TEST_EQ(output, 3);
}
{
auto output = boost::compat::to_underlying(scoped::value);
BOOST_TEST_TRAIT_SAME(decltype(output), int);
BOOST_TEST_EQ(output, 4);
}
{
auto output = boost::compat::to_underlying(scoped_int8_t::value);
BOOST_TEST_TRAIT_SAME(decltype(output), std::int8_t);
BOOST_TEST_EQ(output, 5);
}
{
auto output = boost::compat::to_underlying(scoped_uint16_t::value);
BOOST_TEST_TRAIT_SAME(decltype(output), std::uint16_t);
BOOST_TEST_EQ(output, 6);
}
return boost::report_errors();
}