mirror of
https://github.com/boostorg/compat.git
synced 2026-01-19 16:12:15 +00:00
Compare commits
21 Commits
boost-1.89
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ce75ac955 | ||
|
|
0776d62a95 | ||
|
|
904b80b8a1 | ||
|
|
ffaadc079d | ||
|
|
ab09450342 | ||
|
|
79ca9646ea | ||
|
|
6b9e52c284 | ||
|
|
4c9e9079c1 | ||
|
|
e522245e9c | ||
|
|
cef4d529d0 | ||
|
|
1e3cb9cc7a | ||
|
|
1226bab251 | ||
|
|
f9dd6181fb | ||
|
|
db39b5075c | ||
|
|
f72aeb4e59 | ||
|
|
8e7e16e9c3 | ||
|
|
f897f32064 | ||
|
|
a5a56ee5c0 | ||
|
|
72ff680a72 | ||
|
|
94b1675762 | ||
|
|
694b78df7a |
@@ -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 []) +
|
||||
@@ -160,31 +159,24 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
),
|
||||
|
||||
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(
|
||||
@@ -202,40 +194,47 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 24.04 Clang 17 UBSAN",
|
||||
"Linux 24.04 Clang 17",
|
||||
"cppalliance/droneubuntu2404:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '11,14,17,20,2b' } + ubsan,
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '11,14,17,20,2b' },
|
||||
"clang-17",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 24.04 Clang 17 ASAN",
|
||||
"Linux 24.04 Clang 18",
|
||||
"cppalliance/droneubuntu2404:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '11,14,17,20,2b' } + asan,
|
||||
"clang-17",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 24.04 Clang 18 UBSAN",
|
||||
"cppalliance/droneubuntu2404:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '11,14,17,20,2b' } + ubsan,
|
||||
{ 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",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 24.10 Clang 19",
|
||||
"cppalliance/droneubuntu2410: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,
|
||||
@@ -258,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",
|
||||
|
||||
31
.github/workflows/ci.yml
vendored
31
.github/workflows/ci.yml
vendored
@@ -73,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"
|
||||
@@ -172,18 +177,30 @@ jobs:
|
||||
- toolset: clang
|
||||
compiler: clang++-19
|
||||
cxxstd: "03,11,14,17,20,2b"
|
||||
container: ubuntu:24.10
|
||||
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,2b"
|
||||
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}}
|
||||
|
||||
@@ -310,9 +327,9 @@ jobs:
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
- os: macos-13
|
||||
- os: macos-14
|
||||
- os: macos-15
|
||||
- os: macos-26
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
@@ -359,9 +376,9 @@ jobs:
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
- os: macos-13
|
||||
- os: macos-14
|
||||
- os: macos-15
|
||||
- os: macos-26
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
@@ -418,9 +435,9 @@ jobs:
|
||||
include:
|
||||
- os: ubuntu-22.04
|
||||
- os: ubuntu-24.04
|
||||
- os: macos-13
|
||||
- os: macos-14
|
||||
- os: macos-15
|
||||
- os: macos-26
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@ 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`.
|
||||
|
||||
@@ -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);
|
||||
```
|
||||
|
||||
58
doc/compat/nontype.adoc
Normal file
58
doc/compat/nontype.adoc
Normal 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
|
||||
```
|
||||
@@ -7,11 +7,12 @@ https://www.boost.org/LICENSE_1_0.txt
|
||||
include::bind_back.adoc[]
|
||||
include::bind_front.adoc[]
|
||||
include::function_ref.adoc[]
|
||||
include::move_only_function.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[]
|
||||
|
||||
@@ -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]
|
||||
|
||||
57
doc/compat/to_underlying.adoc
Normal file
57
doc/compat/to_underlying.adoc
Normal 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.
|
||||
37
include/boost/compat/detail/nontype.hpp
Normal file
37
include/boost/compat/detail/nontype.hpp
Normal 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
|
||||
@@ -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,28 +90,24 @@ 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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
22
include/boost/compat/to_underlying.hpp
Normal file
22
include/boost/compat/to_underlying.hpp
Normal 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
|
||||
@@ -117,3 +117,7 @@ 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 ;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,121 +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);
|
||||
|
||||
int x = 2;
|
||||
compat::function_ref<int(F1&, int)> fn2(compat::nontype_t<&F1::m2>{});
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -160,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
|
||||
|
||||
33
test/nontype_test.cpp
Normal file
33
test/nontype_test.cpp
Normal 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
|
||||
75
test/to_underlying_test.cpp
Normal file
75
test/to_underlying_test.cpp
Normal 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();
|
||||
}
|
||||
Reference in New Issue
Block a user