├── .appveyor.yml ├── .clang-format ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── LICENSE.md ├── README.md ├── STATUS.md ├── include └── slb │ ├── detail │ ├── config.hpp │ ├── invoke.hpp │ └── lib.hpp │ ├── functional.hpp │ ├── type_traits.hpp │ └── utility.hpp └── test ├── CMakeLists.txt ├── README.md ├── catch.cpp ├── catch.hpp ├── functional ├── bind.cpp ├── invoke.cpp ├── mem_fn.cpp └── not_fn.cpp ├── type_traits.cpp └── utility.cpp /.appveyor.yml: -------------------------------------------------------------------------------- 1 | # SLB 2 | # 3 | # Copyright Michael Park, 2017 4 | # Copyright Agustin Berge, 2017 5 | # 6 | # Distributed under the Boost Software License, Version 1.0. 7 | # (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 8 | 9 | platform: x64 10 | 11 | environment: 12 | matrix: 13 | # MSVC 14.0 14 | - GENERATOR: Visual Studio 14 2015 Win64 15 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 16 | 17 | # MSVC 14.1 18 | - GENERATOR: Visual Studio 15 2017 Win64 19 | CXXFLAGS: /std:c++14 /permissive- 20 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 21 | 22 | - GENERATOR: Visual Studio 15 2017 Win64 23 | CXXFLAGS: /std:c++latest /permissive- 24 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 25 | 26 | # LLVM 27 | - GENERATOR: Visual Studio 14 2015 Win64 28 | TOOLSET: LLVM-vs2014 29 | CXXFLAGS: /EHsc 30 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 31 | 32 | # MinGW-w64 33 | - GENERATOR: MinGW Makefiles 34 | CXXFLAGS: -std=c++11 35 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 36 | 37 | - GENERATOR: MinGW Makefiles 38 | CXXFLAGS: -std=c++14 39 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 40 | 41 | - GENERATOR: MinGW Makefiles 42 | CXXFLAGS: -std=c++1z 43 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 44 | 45 | branches: 46 | only: 47 | - master 48 | 49 | init: 50 | - ps: | 51 | if ($env:GENERATOR -eq "MinGW Makefiles") { 52 | $env:Path = 'C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin;' + $env:Path 53 | # Workaround for CMake not wanting sh.exe on PATH for MinGW Makefiles 54 | $env:Path = $env:Path -replace 'C:\\Program Files\\Git\\usr\\bin;',$null 55 | } 56 | 57 | build_script: 58 | - echo cmake -G "%GENERATOR%" -T "%TOOLSET%" 59 | - ps: | 60 | if ($env:GENERATOR -eq "MinGW Makefiles") { 61 | $env:CXXFLAGS = $env:CXXFLAGS + ' -Wall -Wextra -Werror -pedantic-errors' 62 | 63 | mkdir build-debug 64 | cd build-debug 65 | cmake -G "$env:GENERATOR" -DCMAKE_BUILD_TYPE=Debug .. 66 | cmake --build . -- -k 67 | ctest --output-on-failure 68 | 69 | cd .. 70 | mkdir build-release 71 | cd build-release 72 | cmake -G "$env:GENERATOR" -DCMAKE_BUILD_TYPE=Release .. 73 | cmake --build . -- -k 74 | ctest --output-on-failure 75 | } else { 76 | $env:CXXFLAGS = $env:CXXFLAGS + ' /W4' 77 | 78 | mkdir build 79 | cd build 80 | if (Test-Path env:TOOLSET) { 81 | cmake -G "$env:GENERATOR" -T "$env:TOOLSET" .. 82 | } else { 83 | cmake -G "$env:GENERATOR" .. 84 | } 85 | cmake --build . --config Debug 86 | ctest --output-on-failure --build-config Debug 87 | cmake --build . --config Release 88 | ctest --output-on-failure --build-config Release 89 | } 90 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | 4 | AlwaysBreakTemplateDeclarations: true 5 | BinPackArguments: false 6 | BinPackParameters: false 7 | PointerAlignment: Left 8 | SortUsingDeclarations: false 9 | ... 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # SLB 2 | # 3 | # Copyright Michael Park, 2017 4 | # Copyright Agustin Berge, 2017 5 | # 6 | # Distributed under the Boost Software License, Version 1.0. 7 | # (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 8 | 9 | language: cpp 10 | sudo: false 11 | 12 | matrix: 13 | include: 14 | # gcc-4.8 15 | - env: VERSION=4.8 CXX_VERSIONS="11;1y" 16 | compiler: gcc 17 | os: linux 18 | addons: 19 | apt: 20 | packages: 21 | - g++-4.8 22 | sources: 23 | - ubuntu-toolchain-r-test 24 | 25 | # gcc-4.9 26 | - env: VERSION=4.9 CXX_VERSIONS="11;14" 27 | compiler: gcc 28 | os: linux 29 | addons: 30 | apt: 31 | packages: 32 | - g++-4.9 33 | sources: 34 | - ubuntu-toolchain-r-test 35 | 36 | # gcc-5 37 | - env: VERSION=5 CXX_VERSIONS="11;14;1z" 38 | compiler: gcc 39 | os: linux 40 | addons: 41 | apt: 42 | packages: 43 | - g++-5 44 | sources: 45 | - ubuntu-toolchain-r-test 46 | 47 | # gcc-6 48 | - env: VERSION=6 CXX_VERSIONS="11;14;1z" 49 | compiler: gcc 50 | os: linux 51 | addons: 52 | apt: 53 | packages: 54 | - g++-6 55 | sources: 56 | - ubuntu-toolchain-r-test 57 | 58 | # gcc-7 59 | - env: VERSION=7 CXX_VERSIONS="11;14;17" CXXFLAGS="-Wno-noexcept-type" 60 | compiler: gcc 61 | os: linux 62 | addons: 63 | apt: 64 | packages: 65 | - g++-7 66 | sources: 67 | - ubuntu-toolchain-r-test 68 | 69 | # clang-3.7 70 | - env: VERSION=3.7 CXX_VERSIONS="11;14" 71 | compiler: clang 72 | os: linux 73 | addons: 74 | apt: 75 | packages: 76 | - clang-3.7 77 | - libstdc++-5-dev 78 | sources: 79 | - ubuntu-toolchain-r-test 80 | - llvm-toolchain-precise-3.7 81 | 82 | # clang-3.8 83 | - env: VERSION=3.8 CXX_VERSIONS="11;14" 84 | compiler: clang 85 | os: linux 86 | addons: 87 | apt: 88 | packages: 89 | - clang-3.8 90 | - libstdc++-5-dev 91 | sources: 92 | - ubuntu-toolchain-r-test 93 | - llvm-toolchain-precise-3.8 94 | 95 | # clang-3.9 96 | - env: VERSION=3.9 CXX_VERSIONS="11;14;1z" 97 | compiler: clang 98 | os: linux 99 | addons: 100 | apt: 101 | packages: 102 | - clang-3.9 103 | - libstdc++-6-dev 104 | sources: 105 | - ubuntu-toolchain-r-test 106 | - llvm-toolchain-trusty-3.9 107 | 108 | # clang-4 109 | - env: VERSION=4.0 CXX_VERSIONS="11;14;1z" 110 | compiler: clang 111 | os: linux 112 | addons: 113 | apt: 114 | packages: 115 | - clang-4.0 116 | - libstdc++-6-dev 117 | sources: 118 | - ubuntu-toolchain-r-test 119 | - llvm-toolchain-trusty-4.0 120 | 121 | # clang-5 122 | - env: VERSION=5.0 CXX_VERSIONS="11;14;17" 123 | compiler: clang 124 | os: linux 125 | addons: 126 | apt: 127 | packages: 128 | - clang-5.0 129 | - libstdc++-7-dev 130 | sources: 131 | - ubuntu-toolchain-r-test 132 | - llvm-toolchain-trusty-5.0 133 | 134 | # Xcode 6.4 135 | - env: CXX_VERSIONS="11;14" 136 | compiler: clang 137 | os: osx 138 | osx_image: xcode6.4 139 | 140 | # Xcode 7.3 141 | - env: CXX_VERSIONS="11;14;1z" 142 | compiler: clang 143 | os: osx 144 | osx_image: xcode7.3 145 | 146 | # Xcode 8.3 147 | - env: CXX_VERSIONS="11;14;1z" 148 | compiler: clang 149 | os: osx 150 | osx_image: xcode8.3 151 | 152 | # Xcode 9.1 153 | - env: CXX_VERSIONS="11;14;1z" 154 | compiler: clang 155 | os: osx 156 | osx_image: xcode9.1 157 | 158 | branches: 159 | only: 160 | - master 161 | 162 | install: 163 | - | 164 | if [ -n "${VERSION}" ]; then 165 | export CC="${CC}-${VERSION}" 166 | export CXX="${CXX}-${VERSION}" 167 | fi 168 | 169 | script: 170 | - | 171 | python - < 26 | $) 27 | 28 | add_library(SLB::SLB ALIAS SLB) 29 | 30 | # Test 31 | if(BUILD_TESTING AND SLB_BUILD_TESTING) 32 | enable_testing() 33 | add_subdirectory(test) 34 | endif() 35 | 36 | # Config 37 | include(CMakePackageConfigHelpers) 38 | 39 | file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/slb-config.cmake.in [[ 40 | # SLB 41 | # 42 | # Copyright Michael Park, 2017 43 | # Copyright Agustin Berge, 2017 44 | # 45 | # Distributed under the Boost Software License, Version 1.0. 46 | # (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 47 | 48 | # - Config file for SLB 49 | # 50 | # SLB_INCLUDE_DIRS - include directories 51 | # SLB_LIBRARIES - libraries to link against 52 | # 53 | # The following `IMPORTED` target is also defined: 54 | # 55 | # SLB::SLB 56 | @PACKAGE_INIT@ 57 | include(${CMAKE_CURRENT_LIST_DIR}/slb-targets.cmake) 58 | 59 | get_target_property(SLB_INCLUDE_DIRS SLB::SLB INTERFACE_INCLUDE_DIRECTORIES) 60 | set_and_check(SLB_INCLUDE_DIRS "${SLB_INCLUDE_DIRS}") 61 | set(SLB_LIBRARIES SLB::SLB) 62 | ]]) 63 | 64 | configure_package_config_file( 65 | ${CMAKE_CURRENT_BINARY_DIR}/slb-config.cmake.in 66 | ${CMAKE_CURRENT_BINARY_DIR}/slb-config.cmake 67 | INSTALL_DESTINATION lib/cmake/slb 68 | NO_CHECK_REQUIRED_COMPONENTS_MACRO) 69 | 70 | # Install 71 | install(DIRECTORY include/slb DESTINATION include) 72 | install(TARGETS SLB EXPORT _targets) 73 | install(EXPORT _targets 74 | DESTINATION lib/cmake/slb 75 | NAMESPACE SLB:: 76 | FILE slb-targets.cmake) 77 | 78 | install( 79 | FILES ${CMAKE_CURRENT_BINARY_DIR}/slb-config.cmake 80 | DESTINATION lib/cmake/slb) 81 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SLB 2 | 3 | > C++ Standard Library Backport 4 | 5 | [![travis][badge.travis]][travis] 6 | [![appveyor][badge.appveyor]][appveyor] 7 | [![license][badge.license]][license] 8 | 9 | [badge.travis]: https://travis-ci.org/mpark/slb.svg?branch=master 10 | [badge.appveyor]: https://ci.appveyor.com/api/projects/status/github/mpark/slb?branch=master&svg=true 11 | [badge.license]: https://img.shields.io/badge/license-boost-blue.svg 12 | 13 | [travis]: https://travis-ci.org/mpark/slb 14 | [appveyor]: https://ci.appveyor.com/project/mpark/slb 15 | [license]: https://github.com/mpark/slb/blob/master/LICENSE.md 16 | 17 | ## Introduction 18 | 19 | __SLB__ is an implementation of the latest version of the C++ standard library 20 | backported to __C++11__/__14__/__17__. 21 | 22 | ## Documentation 23 | 24 | - [C++ Working Draft](https://wg21.link/standard) 25 | - [eel.is/c++draft](http://eel.is/c++draft) 26 | 27 | ## CMake Variables 28 | 29 | - __`SLB_BUILD_TESTING`__: `BOOL` 30 | 31 | Build unit tests. 32 | 33 | ## Status 34 | 35 | Refer to [STATUS.md](STATUS.md). 36 | 37 | ## Unit Tests 38 | 39 | Refer to [test/README.md](test/README.md). 40 | 41 | ## License 42 | 43 | Distributed under the [Boost Software License, Version 1.0](LICENSE.md). 44 | -------------------------------------------------------------------------------- /include/slb/detail/config.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | SLB.Detail.Config 3 | 4 | Copyright Michael Park, 2017 5 | 6 | Distributed under the Boost Software License, Version 1.0. 7 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 8 | */ 9 | 10 | #ifndef SLB_DETAIL_CONFIG_HPP 11 | #define SLB_DETAIL_CONFIG_HPP 12 | 13 | // MSVC 2015 Update 3. 14 | #if __cplusplus < 201103L && (!defined(_MSC_VER) || _MSC_FULL_VER < 190024210) 15 | #error "SLB requires C++11 support." 16 | #endif 17 | 18 | #ifndef __has_builtin 19 | #define __has_builtin(x) 0 20 | #endif 21 | 22 | #ifndef __has_include 23 | #define __has_include(x) 0 24 | #endif 25 | 26 | #ifndef __has_feature 27 | #define __has_feature(x) 0 28 | #endif 29 | 30 | #ifndef __has_warning 31 | #define __has_warning(x) 0 32 | #endif 33 | 34 | // N3652: "Relaxing constraints on constexpr functions / constexpr member 35 | // functions and implicit const" 36 | #if (defined(__cpp_constexpr) && __cpp_constexpr >= 201304) || \ 37 | (defined(_MSC_VER) && _MSC_VER >= 1910) 38 | #define SLB_CXX14_CONSTEXPR constexpr 39 | #else 40 | #define SLB_CXX14_CONSTEXPR 41 | #endif 42 | 43 | // N3651: "Variable Templates" 44 | #if (defined(__cpp_variable_templates) && \ 45 | __cpp_variable_templates >= 201304) || \ 46 | (defined(_MSC_VER) && _MSC_VER >= 1900) 47 | #define SLB_HAS_CXX14_VARIABLE_TEMPLATES 1 48 | #else 49 | #define SLB_HAS_CXX14_VARIABLE_TEMPLATES 0 50 | #endif 51 | 52 | // P0386: "Inline Variables" 53 | #if (defined(__cpp_inline_variables) && __cpp_inline_variables >= 201606) || \ 54 | (defined(_MSC_VER) && _MSC_VER >= 1912 && _HAS_CXX17) 55 | #define SLB_CXX17_INLINE_VARIABLE inline 56 | #else 57 | #define SLB_CXX17_INLINE_VARIABLE 58 | #endif 59 | 60 | #endif // SLB_DETAIL_CONFIG_HPP 61 | -------------------------------------------------------------------------------- /include/slb/detail/invoke.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | SLB.Detail.Invoke 3 | 4 | Copyright Michael Park, 2017 5 | Copyright Agustin Berge, 2017 6 | 7 | Distributed under the Boost Software License, Version 1.0. 8 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 9 | */ 10 | 11 | #ifndef SLB_DETAIL_INVOKE_HPP 12 | #define SLB_DETAIL_INVOKE_HPP 13 | 14 | #include "config.hpp" 15 | #include "lib.hpp" 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | namespace slb { 22 | namespace detail { 23 | namespace invoke_impl { 24 | 25 | //////////////////////////////////////////////////////////////////////////////// 26 | template 27 | struct is_reference_wrapper : std::false_type {}; 28 | 29 | template 30 | struct is_reference_wrapper> : std::true_type {}; 31 | 32 | //////////////////////////////////////////////////////////////////////////////// 33 | struct ref_tag {}; 34 | struct ref_wrapper_tag {}; 35 | struct ptr_tag {}; 36 | 37 | template 38 | struct dispatch_mem_ptr; 39 | 40 | // `ref_tag` when `pm` is a pointer to member of a class `C` and 41 | // `is_base_of_v>` is `true`; 42 | template 43 | struct dispatch_mem_ptr< 44 | C, 45 | T, 46 | typename std::enable_if< 47 | std::is_base_of::type>::value>:: 48 | type> { 49 | using type = ref_tag; 50 | }; 51 | 52 | // `ref_wrapper_tag` when `pm` is a pointer to member of a class `C` and 53 | // `remove_cvref_t` is a specialization of `reference_wrapper`; 54 | template 55 | struct dispatch_mem_ptr< 56 | C, 57 | T, 58 | typename std::enable_if::type>::value>::type> { 60 | using type = ref_wrapper_tag; 61 | }; 62 | 63 | // `ptr_tag` when `pm` is a pointer to member of a class `C` and `T` does not 64 | // satisfy the previous two items; 65 | template 66 | struct dispatch_mem_ptr { 67 | using type = ptr_tag; 68 | }; 69 | 70 | //////////////////////////////////////////////////////////////////////////////// 71 | template 72 | struct mem_obj_ptr_result {}; 73 | 74 | template 75 | struct mem_obj_ptr_result().*std::declval()))> { 79 | using type = decltype(std::declval().*std::declval()); 80 | }; 81 | 82 | template 83 | struct mem_obj_ptr_result().get().* 86 | std::declval()))> { 87 | using type = decltype(std::declval().get().*std::declval()); 88 | }; 89 | 90 | template 91 | struct mem_obj_ptr_result()).* 94 | std::declval()))> { 95 | using type = decltype((*std::declval()).*std::declval()); 96 | }; 97 | 98 | //////////////////////////////////////////////////////////////////////////////// 99 | template 100 | class mem_obj_ptr; 101 | 102 | template 103 | class mem_obj_ptr { 104 | T C::*pm; 105 | 106 | private: 107 | // `t1.*pm` when `N == 1` and `pm` is a pointer to data member of a class `C` 108 | // and `is_base_of_v>` is `true`; 109 | template 110 | static constexpr R call(ref_tag, T C::*pm, T1&& t1) noexcept { 111 | return std::forward(t1).*pm; 112 | } 113 | 114 | // `t1.get().*pm` when `N == 1` and `pm` is a pointer to data member of a 115 | // class `C` and `remove_cvref_t` is a specialization of 116 | // `reference_wrapper`; 117 | template 118 | static constexpr R call(ref_wrapper_tag, T C::*pm, T1&& t1) noexcept { 119 | return t1.get().*pm; 120 | } 121 | 122 | // `(*t1).*pm` when `N == 1` and `pm` is a pointer to data member of a class 123 | // `C` and `t1` does not satisfy the previous two items; 124 | template 125 | static constexpr R 126 | call(ptr_tag, T C::*pm, T1&& t1) noexcept(noexcept(*std::forward(t1))) { 127 | return (*std::forward(t1)).*pm; 128 | } 129 | 130 | public: 131 | constexpr mem_obj_ptr(T C::*pm) noexcept : pm(pm) {} 132 | 133 | template ::type, 135 | typename R = typename mem_obj_ptr_result::type> 136 | constexpr R operator()(T1&& t1) const 137 | noexcept(noexcept(call(Tag{}, pm, std::forward(t1)))) { 138 | return call(Tag{}, pm, std::forward(t1)); 139 | } 140 | }; 141 | 142 | //////////////////////////////////////////////////////////////////////////////// 143 | template 144 | struct p0704_noexcept { 145 | using type = T1; 146 | }; 147 | template 148 | struct p0704 { 149 | using type = typename p0704_noexcept::type; 150 | }; 151 | 152 | // P0704: Fixing const-qualified pointers to members 153 | // In a .* expression whose object expression is an rvalue, the program is 154 | // ill-formed if the second operand is a pointer to member function with whose 155 | // ref-qualifier is &, unless its cv-qualifier-seq is const. 156 | #if __cplusplus <= 201703L // C++2a 157 | template 158 | struct p0704_noexcept { 159 | using type = T1&; 160 | }; 161 | template 162 | struct p0704_noexcept { 163 | using type = T1&; 164 | }; 165 | template 166 | struct p0704 { 167 | using type = T1&; 168 | }; 169 | template 170 | struct p0704 { 171 | using type = T1&; 172 | }; 173 | #endif 174 | 175 | //////////////////////////////////////////////////////////////////////////////// 176 | template 177 | struct apply_clang_workaround_noexcept { 178 | using type = void; 179 | }; 180 | template 181 | struct apply_clang_workaround : apply_clang_workaround_noexcept {}; 182 | 183 | // clang accepts invalid calls to non-const members on references to const 184 | // derived class up to version 5.0. 185 | #if defined(__clang__) 186 | template 187 | struct disable_if_const_derived 188 | : std::enable_if< 189 | !std::is_const::type>::value || 190 | !std::is_base_of::type>::value> {}; 192 | 193 | template 194 | struct apply_clang_workaround_noexcept 195 | : disable_if_const_derived {}; 196 | template 197 | struct apply_clang_workaround_noexcept 198 | : disable_if_const_derived {}; 199 | template 200 | struct apply_clang_workaround 201 | : disable_if_const_derived {}; 202 | template 203 | struct apply_clang_workaround 204 | : disable_if_const_derived {}; 205 | #endif 206 | 207 | //////////////////////////////////////////////////////////////////////////////// 208 | template 209 | struct mem_fun_ptr_result {}; 210 | 211 | template 212 | struct mem_fun_ptr_result().*std::declval())( 216 | std::declval()...)))> { 217 | using type = 218 | decltype((std::declval().*std::declval())(std::declval()...)); 219 | }; 220 | 221 | template 222 | struct mem_fun_ptr_result().get().* 225 | std::declval())( 226 | std::declval()...)))> { 227 | using type = decltype( 228 | (std::declval().get().*std::declval())(std::declval()...)); 229 | }; 230 | 231 | template 232 | struct mem_fun_ptr_result()).*std::declval())( 236 | std::declval()...)))> { 237 | using type = decltype( 238 | ((*std::declval()).*std::declval())(std::declval()...)); 239 | }; 240 | 241 | //////////////////////////////////////////////////////////////////////////////// 242 | template 243 | class mem_fun_ptr; 244 | 245 | template 246 | class mem_fun_ptr { 247 | T C::*pm; 248 | 249 | private: 250 | // `(t1.*pm)(t2, ..., tN)` when `pm` is a pointer to a member function of a 251 | // class `C` and `is_base_of_v>` is 252 | // `true`; 253 | template 254 | static constexpr R call(ref_tag, T C::*pm, T1&& t1, Tn&&... tn) noexcept( 255 | noexcept((std::forward(t1).*pm)(std::forward(tn)...))) { 256 | return (std::forward(t1).*pm)(std::forward(tn)...); 257 | } 258 | 259 | // `(t1.get().*pm)(t2, ..., tN)` when `pm` is a pointer to a member function 260 | // of a class `C` and `remove_cvref_t` is a specialization of 261 | // `reference_wrapper`; 262 | template 263 | static constexpr R 264 | call(ref_wrapper_tag, 265 | T C::*pm, 266 | T1&& t1, 267 | Tn&&... tn) noexcept(noexcept((t1.get().*pm)(std::forward(tn)...))) { 268 | return (t1.get().*pm)(std::forward(tn)...); 269 | } 270 | 271 | // `((*t1).*pm)(t2, ..., tN)` when `pm` is a pointer to a member function of a 272 | // class `C` and `t1` does not satisfy the previous two items; 273 | template 274 | static constexpr R call(ptr_tag, T C::*pm, T1&& t1, Tn&&... tn) noexcept( 275 | noexcept(((*std::forward(t1)).*pm)(std::forward(tn)...))) { 276 | return ((*std::forward(t1)).*pm)(std::forward(tn)...); 277 | } 278 | 279 | public: 280 | constexpr mem_fun_ptr(T C::*pm) noexcept : pm(pm) {} 281 | 282 | template ::type, 285 | typename Tag = typename dispatch_mem_ptr::type, 286 | typename R = 287 | typename mem_fun_ptr_result::type, 288 | typename = typename apply_clang_workaround::type> 289 | constexpr R operator()(T1&& t1, Tn&&... tn) const noexcept(noexcept( 290 | call(Tag{}, pm, std::forward(t1), std::forward(tn)...))) { 291 | return call(Tag{}, pm, std::forward(t1), std::forward(tn)...); 292 | } 293 | }; 294 | 295 | } // namespace invoke_impl 296 | 297 | // We don't use `std::is_function` here since some libstdc++ versions fail to 298 | // classify function types with noexcept specifiers. 299 | 300 | template 301 | struct mem_fn_result {}; 302 | 303 | template 304 | struct mem_fn_result { 305 | using type = 306 | typename std::conditional::value, 307 | invoke_impl::mem_fun_ptr, 308 | invoke_impl::mem_obj_ptr>::type; 309 | }; 310 | 311 | //////////////////////////////////////////////////////////////////////////////// 312 | namespace invoke_impl { 313 | 314 | template ::type> 315 | struct dispatch_invoke { 316 | using type = F&&; 317 | }; 318 | 319 | template 320 | struct dispatch_invoke { 321 | using type = typename mem_fn_result::type; 322 | }; 323 | 324 | } // namespace invoke_impl 325 | 326 | template 327 | constexpr auto invoke(F&& f, Args&&... args) noexcept( 328 | noexcept(typename invoke_impl::dispatch_invoke::type(std::forward(f))( 329 | std::forward(args)...))) 330 | -> decltype(typename invoke_impl::dispatch_invoke::type( 331 | std::forward(f))(std::forward(args)...)) { 332 | return typename invoke_impl::dispatch_invoke::type(std::forward(f))( 333 | std::forward(args)...); 334 | } 335 | 336 | //////////////////////////////////////////////////////////////////////////////// 337 | namespace invoke_impl { 338 | 339 | // `INVOKE(f, t1, t2, ..., tN)` implicitly converted to `R`. 340 | template ::type> 341 | struct invoke_guard { 342 | private: 343 | static R conversion(R) noexcept; 344 | 345 | public: 346 | template 347 | static constexpr auto call(F&& f, Args&&... args) noexcept( 348 | noexcept(conversion(detail::invoke(std::forward(f), 349 | std::forward(args)...)))) 350 | -> decltype(conversion(detail::invoke(std::forward(f), 351 | std::forward(args)...))) { 352 | return detail::invoke(std::forward(f), std::forward(args)...); 353 | } 354 | }; 355 | 356 | // `static_cast(INVOKE(f, t1, t2, ..., tN))` if `R` is _cv_ `void`. 357 | template 358 | struct invoke_guard { 359 | template 360 | static constexpr auto call(F&& f, Args&&... args) noexcept( 361 | noexcept(detail::invoke(std::forward(f), std::forward(args)...))) 362 | -> decltype((void)(detail::invoke(std::forward(f), 363 | std::forward(args)...))) { 364 | return static_cast( 365 | detail::invoke(std::forward(f), std::forward(args)...)); 366 | } 367 | }; 368 | 369 | } // namespace invoke_impl 370 | 371 | template 372 | constexpr auto invoke_r(F&& f, Args&&... args) noexcept( 373 | noexcept(invoke_impl::invoke_guard::call(std::forward(f), 374 | std::forward(args)...))) 375 | -> decltype(invoke_impl::invoke_guard::call( 376 | std::forward(f), std::forward(args)...)) { 377 | return invoke_impl::invoke_guard::call(std::forward(f), 378 | std::forward(args)...); 379 | } 380 | 381 | } // namespace detail 382 | } // namespace slb 383 | 384 | #endif // SLB_DETAIL_INVOKE_HPP 385 | -------------------------------------------------------------------------------- /include/slb/detail/lib.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | SLB.TypeTraits 3 | 4 | Copyright Michael Park, 2017 5 | Copyright Agustin Berge, 2017 6 | 7 | Distributed under the Boost Software License, Version 1.0. 8 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 9 | */ 10 | 11 | #ifndef SLB_DETAIL_LIB_HPP 12 | #define SLB_DETAIL_LIB_HPP 13 | 14 | #include 15 | 16 | namespace slb { 17 | namespace detail { 18 | namespace lib { 19 | 20 | template 21 | struct always_false : std::false_type {}; 22 | 23 | //////////////////////////////////////////////////////////////////////////////// 24 | #ifdef _MSC_VER 25 | #pragma warning(push) 26 | #pragma warning(disable : 4180) // qualifier applied to function type has no 27 | // meaning; ignored 28 | #endif 29 | template 30 | struct is_function : std::integral_constant::value && 32 | !std::is_reference::value> { 33 | }; 34 | #ifdef _MSC_VER 35 | #pragma warning(pop) 36 | #endif 37 | 38 | //////////////////////////////////////////////////////////////////////////////// 39 | template 40 | struct remove_cvref { 41 | using type = 42 | typename std::remove_cv::type>::type; 43 | }; 44 | 45 | } // namespace lib 46 | } // namespace detail 47 | } // namespace slb 48 | 49 | #endif // SLB_DETAIL_LIB_HPP 50 | -------------------------------------------------------------------------------- /include/slb/functional.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | SLB.Functional 3 | 4 | Copyright Michael Park, 2017 5 | Copyright Agustin Berge, 2017 6 | 7 | Distributed under the Boost Software License, Version 1.0. 8 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 9 | */ 10 | 11 | #ifndef SLB_FUNCTIONAL_HPP 12 | #define SLB_FUNCTIONAL_HPP 13 | 14 | /* 15 | 16 | Header synopsis [functional.syn] 17 | 18 | namespace std { 19 | // [func.invoke], invoke 20 | template 21 | invoke_result_t invoke(F&& f, Args&&... args) 22 | noexcept(is_nothrow_invocable_v); 23 | 24 | // [refwrap], reference_wrapper 25 | template class reference_wrapper; 26 | 27 | template reference_wrapper ref(T&) noexcept; 28 | template reference_wrapper cref(const T&) noexcept; 29 | template void ref(const T&&) = delete; 30 | template void cref(const T&&) = delete; 31 | 32 | template reference_wrapper ref(reference_wrapper) noexcept; 33 | template reference_wrapper cref(reference_wrapper) 34 | noexcept; 35 | 36 | // [arithmetic.operations], arithmetic operations 37 | template struct plus; 38 | template struct minus; 39 | template struct multiplies; 40 | template struct divides; 41 | template struct modulus; 42 | template struct negate; 43 | template <> struct plus; 44 | template <> struct minus; 45 | template <> struct multiplies; 46 | template <> struct divides; 47 | template <> struct modulus; 48 | template <> struct negate; 49 | 50 | // [comparisons], comparisons 51 | template struct equal_to; 52 | template struct not_equal_to; 53 | template struct greater; 54 | template struct less; 55 | template struct greater_equal; 56 | template struct less_equal; 57 | template <> struct equal_to; 58 | template <> struct not_equal_to; 59 | template <> struct greater; 60 | template <> struct less; 61 | template <> struct greater_equal; 62 | template <> struct less_equal; 63 | 64 | // [logical.operations], logical operations 65 | template struct logical_and; 66 | template struct logical_or; 67 | template struct logical_not; 68 | template <> struct logical_and; 69 | template <> struct logical_or; 70 | template <> struct logical_not; 71 | 72 | // [bitwise.operations], bitwise operations 73 | template struct bit_and; 74 | template struct bit_or; 75 | template struct bit_xor; 76 | template struct bit_not; 77 | template <> struct bit_and; 78 | template <> struct bit_or; 79 | template <> struct bit_xor; 80 | template <> struct bit_not; 81 | 82 | // [func.not_fn], function template not_fn 83 | template unspecified not_fn(F&& f); 84 | 85 | // [func.bind], bind 86 | template struct is_bind_expression; 87 | template struct is_placeholder; 88 | 89 | template 90 | unspecified bind(F&&, BoundArgs&&...); 91 | template 92 | unspecified bind(F&&, BoundArgs&&...); 93 | 94 | namespace placeholders { 95 | // M is the implementation-defined number of placeholders 96 | see below _1; 97 | see below _2; 98 | ... 99 | see below _M; 100 | } 101 | 102 | // [func.memfn], member function adaptors 103 | template 104 | unspecified mem_fn(R T::*) noexcept; 105 | 106 | // [func.wrap], polymorphic function wrappers 107 | class bad_function_call; 108 | 109 | template class function; // not defined 110 | template class function; 111 | 112 | template 113 | void swap(function&, function&) noexcept; 114 | 115 | template 116 | bool operator==(const function&, nullptr_t) noexcept; 117 | template 118 | bool operator==(nullptr_t, const function&) noexcept; 119 | template 120 | bool operator!=(const function&, nullptr_t) noexcept; 121 | template 122 | bool operator!=(nullptr_t, const function&) noexcept; 123 | 124 | // [func.search], searchers 125 | template> 126 | class default_searcher; 127 | 128 | template::value_type>, 131 | class BinaryPredicate = equal_to<>> 132 | class boyer_moore_searcher; 133 | 134 | template::value_type>, 137 | class BinaryPredicate = equal_to<>> 138 | class boyer_moore_horspool_searcher; 139 | 140 | // [unord.hash], hash function primary template 141 | template 142 | struct hash; 143 | 144 | // [func.bind], function object binders 145 | template 146 | inline constexpr bool is_bind_expression_v = is_bind_expression::value; 147 | template 148 | inline constexpr int is_placeholder_v = is_placeholder::value; 149 | } 150 | 151 | */ 152 | 153 | #include 154 | #include 155 | #include 156 | 157 | #include "detail/config.hpp" 158 | #include "detail/invoke.hpp" 159 | #include "type_traits.hpp" 160 | 161 | namespace slb { 162 | 163 | // [func.invoke], invoke 164 | 165 | // We only enable the C++17 implementation under C++2a here to account for 166 | // P0704: "Fixing const-qualified pointers to members". 167 | 168 | #if __cpp_lib_invoke /* C++17 */ && __cplusplus > 201703L /* C++2a */ 169 | using std::invoke; 170 | #else 171 | template 172 | typename slb::invoke_result::type 173 | invoke(F&& f, 174 | Args&&... args) noexcept(slb::is_nothrow_invocable::value) { 175 | return detail::invoke(std::forward(f), std::forward(args)...); 176 | } 177 | #endif 178 | 179 | // [func.not_fn], function template not_fn 180 | 181 | // We only enable the C++17 implementation under C++2a here to account for 182 | // P0704: "Fixing const-qualified pointers to members" and LWG2210: "INVOKE-ing 183 | // a pointer to member with a `reference_wrapper` as the object expression". 184 | 185 | #if __cpp_lib_not_fn /* C++17 */ && __cplusplus > 201703L /* C++2a */ 186 | using std::not_fn; 187 | #else 188 | namespace detail { 189 | struct not_fn_tag { 190 | explicit not_fn_tag() = default; 191 | }; 192 | 193 | template 194 | class not_fn_result { 195 | FD fd; 196 | 197 | public: 198 | template 199 | not_fn_result(not_fn_tag, F&& f) : fd(std::forward(f)) {} 200 | 201 | not_fn_result(not_fn_result&&) = default; 202 | not_fn_result(not_fn_result const&) = default; 203 | 204 | template 205 | auto operator()(Args&&... args) & 206 | noexcept(noexcept(!detail::invoke(std::declval(), 207 | std::forward(args)...))) 208 | -> decltype(!detail::invoke(std::declval(), 209 | std::forward(args)...)) { 210 | return !detail::invoke(fd, std::forward(args)...); 211 | } 212 | 213 | template 214 | auto operator()(Args&&... args) const& noexcept(noexcept( 215 | !detail::invoke(std::declval(), std::forward(args)...))) 216 | -> decltype(!detail::invoke(std::declval(), 217 | std::forward(args)...)) { 218 | return !detail::invoke(fd, std::forward(args)...); 219 | } 220 | 221 | template 222 | auto operator()(Args&&... args) && 223 | noexcept(noexcept(!detail::invoke(std::declval(), 224 | std::forward(args)...))) 225 | -> decltype(!detail::invoke(std::declval(), 226 | std::forward(args)...)) { 227 | return !detail::invoke(std::move(fd), std::forward(args)...); 228 | } 229 | 230 | // gcc finds calls on const rvalues ambiguous up to version 4.8. 231 | #if !defined(__GNUC__) || (__GNUC__ > 4) || \ 232 | ((__GNUC__ == 4) && (__GNUC_MINOR__ > 8)) 233 | template 234 | auto operator()(Args&&... args) const&& noexcept(noexcept( 235 | !detail::invoke(std::declval(), std::forward(args)...))) 236 | -> decltype(!detail::invoke(std::declval(), 237 | std::forward(args)...)) { 238 | return !detail::invoke(std::move(fd), std::forward(args)...); 239 | } 240 | #endif 241 | }; 242 | } // namespace detail 243 | 244 | template ::type> 245 | detail::not_fn_result not_fn(F&& f) { 246 | static_assert(std::is_move_constructible::value && 247 | std::is_convertible::value, 248 | "FD shall satisfy the requirements of MoveConstructible"); 249 | static_assert(std::is_constructible::value, 250 | "is_constructible_v shall be true"); 251 | return {detail::not_fn_tag{}, std::forward(f)}; 252 | } 253 | #endif 254 | 255 | // [func.bind], bind 256 | 257 | #if SLB_INTEGRAL_CONSTANT == 2 // C++14 258 | using std::is_bind_expression; 259 | using std::is_placeholder; 260 | #else 261 | template 262 | struct is_bind_expression 263 | : slb::bool_constant::value> {}; 264 | 265 | template 266 | struct is_placeholder 267 | : slb::integral_constant::value> {}; 268 | #endif 269 | 270 | // We only enable the C++17 implementation under C++2a here to account for 271 | // P0704: "Fixing const-qualified pointers to members" and LWG2210: "INVOKE-ing 272 | // a pointer to member with a `reference_wrapper` as the object expression". 273 | 274 | #if __cpp_lib_invoke /* C++17 */ && __cplusplus > 201703L /* C++2a */ 275 | using std::bind; 276 | #else 277 | namespace detail { 278 | struct bind_tag { 279 | explicit bind_tag() = default; 280 | }; 281 | 282 | template 283 | class bound { 284 | FD fd; 285 | 286 | public: 287 | template 288 | bound(bind_tag, F&& f) : fd(std::forward(f)) {} 289 | 290 | template 291 | auto operator()(Args&&... args) noexcept(noexcept( 292 | detail::invoke(std::declval(), std::forward(args)...))) 293 | -> decltype(detail::invoke(std::declval(), 294 | std::forward(args)...)) { 295 | return detail::invoke(fd, std::forward(args)...); 296 | } 297 | 298 | template 299 | auto operator()(Args&&... args) const 300 | noexcept(noexcept(detail::invoke(std::declval(), 301 | std::forward(args)...))) 302 | -> decltype(detail::invoke(std::declval(), 303 | std::forward(args)...)) { 304 | return detail::invoke(fd, std::forward(args)...); 305 | } 306 | }; 307 | 308 | template 309 | struct bind_result { 310 | using type = decltype(std::bind(std::declval>(), 311 | std::declval()...)); 312 | }; 313 | 314 | template 315 | class bound_r { 316 | FD fd; 317 | 318 | public: 319 | template 320 | bound_r(bind_tag, F&& f) : fd(std::forward(f)) {} 321 | 322 | template 323 | auto operator()(Args&&... args) noexcept(noexcept( 324 | detail::invoke_r(std::declval(), std::forward(args)...))) 325 | -> decltype(detail::invoke_r(std::declval(), 326 | std::forward(args)...)) { 327 | return detail::invoke_r(fd, std::forward(args)...); 328 | } 329 | 330 | template 331 | auto operator()(Args&&... args) const 332 | noexcept(noexcept(detail::invoke_r(std::declval(), 333 | std::forward(args)...))) 334 | -> decltype(detail::invoke_r(std::declval(), 335 | std::forward(args)...)) { 336 | return detail::invoke_r(fd, std::forward(args)...); 337 | } 338 | }; 339 | 340 | template 341 | struct bind_result_r { 342 | using type = decltype(std::bind(std::declval>(), 343 | std::declval()...)); 344 | }; 345 | } // namespace detail 346 | 347 | template ::type> 350 | typename detail::bind_result::type bind(F&& f, 351 | BoundArgs&&... args) { 352 | return std::bind(detail::bound{detail::bind_tag{}, std::forward(f)}, 353 | std::forward(args)...); 354 | } 355 | 356 | template ::type> 360 | typename detail::bind_result_r::type 361 | bind(F&& f, BoundArgs&&... args) { 362 | return std::bind( 363 | detail::bound_r{detail::bind_tag{}, std::forward(f)}, 364 | std::forward(args)...); 365 | } 366 | #endif 367 | 368 | namespace placeholders = std::placeholders; 369 | 370 | // [func.memfn], member function adaptors 371 | 372 | // We only enable the C++17 implementation under C++2a here to account for 373 | // P0704: "Fixing const-qualified pointers to members" and LWG2210: "INVOKE-ing 374 | // a pointer to member with a `reference_wrapper` as the object expression". 375 | 376 | #if __cpp_lib_invoke /* C++17 */ && __cplusplus > 201703L /* C++2a */ 377 | using std::mem_fn; 378 | #else 379 | template 380 | typename detail::mem_fn_result::type mem_fn(T C::*pm) noexcept { 381 | return pm; 382 | } 383 | #endif 384 | 385 | // [func.bind], function object binders 386 | 387 | #if SLB_HAS_CXX14_VARIABLE_TEMPLATES // C++14 388 | template 389 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_bind_expression_v = 390 | std::is_bind_expression::value; 391 | 392 | template 393 | SLB_CXX17_INLINE_VARIABLE constexpr int is_placeholder_v = 394 | slb::is_placeholder::value; 395 | #endif 396 | 397 | } // namespace slb 398 | 399 | #endif // SLB_FUNCTIONAL_HPP 400 | -------------------------------------------------------------------------------- /include/slb/type_traits.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | SLB.TypeTraits 3 | 4 | Copyright Michael Park, 2017 5 | Copyright Agustin Berge, 2017 6 | 7 | Distributed under the Boost Software License, Version 1.0. 8 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 9 | */ 10 | 11 | #ifndef SLB_TYPE_TRAITS_HPP 12 | #define SLB_TYPE_TRAITS_HPP 13 | 14 | /* 15 | 16 | Header synopsis [meta.type.synop] 17 | 18 | namespace std { 19 | // [meta.help], helper class 20 | template struct integral_constant; 21 | 22 | template 23 | using bool_constant = integral_constant; 24 | using true_type = bool_constant; 25 | using false_type = bool_constant; 26 | 27 | // [meta.unary.cat], primary type categories 28 | template struct is_void; 29 | template struct is_null_pointer; 30 | template struct is_integral; 31 | template struct is_floating_point; 32 | template struct is_array; 33 | template struct is_pointer; 34 | template struct is_lvalue_reference; 35 | template struct is_rvalue_reference; 36 | template struct is_member_object_pointer; 37 | template struct is_member_function_pointer; 38 | template struct is_enum; 39 | template struct is_union; 40 | template struct is_class; 41 | template struct is_function; 42 | 43 | // [meta.unary.comp], composite type categories 44 | template struct is_reference; 45 | template struct is_arithmetic; 46 | template struct is_fundamental; 47 | template struct is_object; 48 | template struct is_scalar; 49 | template struct is_compound; 50 | template struct is_member_pointer; 51 | 52 | // [meta.unary.prop], type properties 53 | template struct is_const; 54 | template struct is_volatile; 55 | template struct is_trivial; 56 | template struct is_trivially_copyable; 57 | template struct is_standard_layout; 58 | template struct is_empty; 59 | template struct is_polymorphic; 60 | template struct is_abstract; 61 | template struct is_final; 62 | template struct is_aggregate; 63 | 64 | template struct is_signed; 65 | template struct is_unsigned; 66 | 67 | template struct is_constructible; 68 | template struct is_default_constructible; 69 | template struct is_copy_constructible; 70 | template struct is_move_constructible; 71 | 72 | template struct is_assignable; 73 | template struct is_copy_assignable; 74 | template struct is_move_assignable; 75 | 76 | template struct is_swappable_with; 77 | template struct is_swappable; 78 | 79 | template struct is_destructible; 80 | 81 | template struct is_trivially_constructible; 82 | template struct is_trivially_default_constructible; 83 | template struct is_trivially_copy_constructible; 84 | template struct is_trivially_move_constructible; 85 | 86 | template struct is_trivially_assignable; 87 | template struct is_trivially_copy_assignable; 88 | template struct is_trivially_move_assignable; 89 | template struct is_trivially_destructible; 90 | 91 | template struct is_nothrow_constructible; 92 | template struct is_nothrow_default_constructible; 93 | template struct is_nothrow_copy_constructible; 94 | template struct is_nothrow_move_constructible; 95 | 96 | template struct is_nothrow_assignable; 97 | template struct is_nothrow_copy_assignable; 98 | template struct is_nothrow_move_assignable; 99 | 100 | template struct is_nothrow_swappable_with; 101 | template struct is_nothrow_swappable; 102 | 103 | template struct is_nothrow_destructible; 104 | 105 | template struct has_virtual_destructor; 106 | 107 | template struct has_unique_object_representations; 108 | 109 | // [meta.unary.prop.query], type property queries 110 | template struct alignment_of; 111 | template struct rank; 112 | template struct extent; 113 | 114 | // [meta.rel], type relations 115 | template struct is_same; 116 | template struct is_base_of; 117 | template struct is_convertible; 118 | 119 | template struct is_invocable; 120 | template struct is_invocable_r; 121 | 122 | template struct is_nothrow_invocable; 123 | template struct is_nothrow_invocable_r; 124 | 125 | // [meta.trans.cv], const-volatile modifications 126 | template struct remove_const; 127 | template struct remove_volatile; 128 | template struct remove_cv; 129 | template struct add_const; 130 | template struct add_volatile; 131 | template struct add_cv; 132 | 133 | template 134 | using remove_const_t = typename remove_const::type; 135 | template 136 | using remove_volatile_t = typename remove_volatile::type; 137 | template 138 | using remove_cv_t = typename remove_cv::type; 139 | template 140 | using add_const_t = typename add_const::type; 141 | template 142 | using add_volatile_t = typename add_volatile::type; 143 | template 144 | using add_cv_t = typename add_cv::type; 145 | 146 | // [meta.trans.ref], reference modifications 147 | template struct remove_reference; 148 | template struct add_lvalue_reference; 149 | template struct add_rvalue_reference; 150 | 151 | template 152 | using remove_reference_t = typename remove_reference::type; 153 | template 154 | using add_lvalue_reference_t = typename add_lvalue_reference::type; 155 | template 156 | using add_rvalue_reference_t = typename add_rvalue_reference::type; 157 | 158 | // [meta.trans.sign], sign modifications 159 | template struct make_signed; 160 | template struct make_unsigned; 161 | 162 | template 163 | using make_signed_t = typename make_signed::type; 164 | template 165 | using make_unsigned_t = typename make_unsigned::type; 166 | 167 | // [meta.trans.arr], array modifications 168 | template struct remove_extent; 169 | template struct remove_all_extents; 170 | 171 | template 172 | using remove_extent_t = typename remove_extent::type; 173 | template 174 | using remove_all_extents_t = typename remove_all_extents::type; 175 | 176 | // [meta.trans.ptr], pointer modifications 177 | template struct remove_pointer; 178 | template struct add_pointer; 179 | 180 | template 181 | using remove_pointer_t = typename remove_pointer::type; 182 | template 183 | using add_pointer_t = typename add_pointer::type; 184 | 185 | // [meta.trans.other], other transformations 186 | template struct type_identity; 187 | template // see [meta.trans.other] 189 | struct aligned_storage; 190 | template struct aligned_union; 191 | template struct remove_cvref; 192 | template struct decay; 193 | template struct enable_if; 194 | template struct conditional; 195 | template struct common_type; 196 | template struct underlying_type; 197 | template struct invoke_result; 198 | 199 | template 200 | using type_identity_t = typename type_identity::type; 201 | template // see [meta.trans.other] 203 | using aligned_storage_t = typename aligned_storage::type; 204 | template 205 | using aligned_union_t = typename aligned_union::type; 206 | template 207 | using remove_cvref_t = typename remove_cvref::type; 208 | template 209 | using decay_t = typename decay::type; 210 | template 211 | using enable_if_t = typename enable_if::type; 212 | template 213 | using conditional_t = typename conditional::type; 214 | template 215 | using common_type_t = typename common_type::type; 216 | template 217 | using underlying_type_t = typename underlying_type::type; 218 | template 219 | using invoke_result_t = typename invoke_result::type; 220 | template 221 | using void_t = void; 222 | 223 | // [meta.logical], logical operator traits 224 | template struct conjunction; 225 | template struct disjunction; 226 | template struct negation; 227 | 228 | // [meta.endian], endian 229 | enum class endian { 230 | little = see below, 231 | big = see below, 232 | native = see below 233 | }; 234 | 235 | // [meta.unary.cat], primary type categories 236 | template 237 | inline constexpr bool is_void_v = is_void::value; 238 | template 239 | inline constexpr bool is_null_pointer_v = is_null_pointer::value; 240 | template 241 | inline constexpr bool is_integral_v = is_integral::value; 242 | template 243 | inline constexpr bool is_floating_point_v = is_floating_point::value; 244 | template 245 | inline constexpr bool is_array_v = is_array::value; 246 | template 247 | inline constexpr bool is_pointer_v = is_pointer::value; 248 | template 249 | inline constexpr bool is_lvalue_reference_v = is_lvalue_reference::value; 250 | template 251 | inline constexpr bool is_rvalue_reference_v = is_rvalue_reference::value; 252 | template 253 | inline constexpr bool is_member_object_pointer_v 254 | = is_member_object_pointer::value; 255 | template 256 | inline constexpr bool is_member_function_pointer_v 257 | = is_member_function_pointer::value; 258 | template 259 | inline constexpr bool is_enum_v = is_enum::value; 260 | template 261 | inline constexpr bool is_union_v = is_union::value; 262 | template 263 | inline constexpr bool is_class_v = is_class::value; 264 | template 265 | inline constexpr bool is_function_v = is_function::value; 266 | 267 | // [meta.unary.comp], composite type categories 268 | template 269 | inline constexpr bool is_reference_v = is_reference::value; 270 | template 271 | inline constexpr bool is_arithmetic_v = is_arithmetic::value; 272 | template 273 | inline constexpr bool is_fundamental_v = is_fundamental::value; 274 | template 275 | inline constexpr bool is_object_v = is_object::value; 276 | template 277 | inline constexpr bool is_scalar_v = is_scalar::value; 278 | template 279 | inline constexpr bool is_compound_v = is_compound::value; 280 | template 281 | inline constexpr bool is_member_pointer_v = is_member_pointer::value; 282 | 283 | // [meta.unary.prop], type properties 284 | template 285 | inline constexpr bool is_const_v = is_const::value; 286 | template 287 | inline constexpr bool is_volatile_v = is_volatile::value; 288 | template 289 | inline constexpr bool is_trivial_v = is_trivial::value; 290 | template 291 | inline constexpr bool is_trivially_copyable_v 292 | = is_trivially_copyable::value; 293 | template 294 | inline constexpr bool is_standard_layout_v = is_standard_layout::value; 295 | template 296 | inline constexpr bool is_empty_v = is_empty::value; 297 | template 298 | inline constexpr bool is_polymorphic_v = is_polymorphic::value; 299 | template 300 | inline constexpr bool is_abstract_v = is_abstract::value; 301 | template 302 | inline constexpr bool is_final_v = is_final::value; 303 | template 304 | inline constexpr bool is_aggregate_v = is_aggregate::value; 305 | template 306 | inline constexpr bool is_signed_v = is_signed::value; 307 | template 308 | inline constexpr bool is_unsigned_v = is_unsigned::value; 309 | template 310 | inline constexpr bool is_constructible_v 311 | = is_constructible::value; 312 | template 313 | inline constexpr bool is_default_constructible_v 314 | = is_default_constructible::value; 315 | template 316 | inline constexpr bool is_copy_constructible_v 317 | = is_copy_constructible::value; 318 | template 319 | inline constexpr bool is_move_constructible_v 320 | = is_move_constructible::value; 321 | template 322 | inline constexpr bool is_assignable_v = is_assignable::value; 323 | template 324 | inline constexpr bool is_copy_assignable_v = is_copy_assignable::value; 325 | template 326 | inline constexpr bool is_move_assignable_v = is_move_assignable::value; 327 | template 328 | inline constexpr bool is_swappable_with_v = is_swappable_with::value; 329 | template 330 | inline constexpr bool is_swappable_v = is_swappable::value; 331 | template 332 | inline constexpr bool is_destructible_v = is_destructible::value; 333 | template 334 | inline constexpr bool is_trivially_constructible_v 335 | = is_trivially_constructible::value; 336 | template 337 | inline constexpr bool is_trivially_default_constructible_v 338 | = is_trivially_default_constructible::value; 339 | template 340 | inline constexpr bool is_trivially_copy_constructible_v 341 | = is_trivially_copy_constructible::value; 342 | template 343 | inline constexpr bool is_trivially_move_constructible_v 344 | = is_trivially_move_constructible::value; 345 | template 346 | inline constexpr bool is_trivially_assignable_v 347 | = is_trivially_assignable::value; 348 | template 349 | inline constexpr bool is_trivially_copy_assignable_v 350 | = is_trivially_copy_assignable::value; 351 | template 352 | inline constexpr bool is_trivially_move_assignable_v 353 | = is_trivially_move_assignable::value; 354 | template 355 | inline constexpr bool is_trivially_destructible_v 356 | = is_trivially_destructible::value; 357 | template 358 | inline constexpr bool is_nothrow_constructible_v 359 | = is_nothrow_constructible::value; 360 | template 361 | inline constexpr bool is_nothrow_default_constructible_v 362 | = is_nothrow_default_constructible::value; 363 | template 364 | inline constexpr bool is_nothrow_copy_constructible_v 365 | = is_nothrow_copy_constructible::value; 366 | template 367 | inline constexpr bool is_nothrow_move_constructible_v 368 | = is_nothrow_move_constructible::value; 369 | template 370 | inline constexpr bool is_nothrow_assignable_v 371 | = is_nothrow_assignable::value; 372 | template 373 | inline constexpr bool is_nothrow_copy_assignable_v 374 | = is_nothrow_copy_assignable::value; 375 | template 376 | inline constexpr bool is_nothrow_move_assignable_v 377 | = is_nothrow_move_assignable::value; 378 | template 379 | inline constexpr bool is_nothrow_swappable_with_v 380 | = is_nothrow_swappable_with::value; 381 | template 382 | inline constexpr bool is_nothrow_swappable_v 383 | = is_nothrow_swappable::value; 384 | template 385 | inline constexpr bool is_nothrow_destructible_v 386 | = is_nothrow_destructible::value; 387 | template 388 | inline constexpr bool has_virtual_destructor_v 389 | = has_virtual_destructor::value; 390 | template 391 | inline constexpr bool has_unique_object_representations_v 392 | = has_unique_object_representations::value; 393 | 394 | // [meta.unary.prop.query], type property queries 395 | template 396 | inline constexpr size_t alignment_of_v = alignment_of::value; 397 | template 398 | inline constexpr size_t rank_v = rank::value; 399 | template 400 | inline constexpr size_t extent_v = extent::value; 401 | 402 | // [meta.rel], type relations 403 | template 404 | inline constexpr bool is_same_v = is_same::value; 405 | template 406 | inline constexpr bool is_base_of_v = is_base_of::value; 407 | template 408 | inline constexpr bool is_convertible_v = is_convertible::value; 409 | template 410 | inline constexpr bool is_invocable_v = is_invocable::value; 411 | template 412 | inline constexpr bool is_invocable_r_v 413 | = is_invocable_r::value; 414 | template 415 | inline constexpr bool is_nothrow_invocable_v 416 | = is_nothrow_invocable::value; 417 | template 418 | inline constexpr bool is_nothrow_invocable_r_v 419 | = is_nothrow_invocable_r::value; 420 | 421 | // [meta.logical], logical operator traits 422 | template 423 | inline constexpr bool conjunction_v = conjunction::value; 424 | template 425 | inline constexpr bool disjunction_v = disjunction::value; 426 | template 427 | inline constexpr bool negation_v = negation::value; 428 | } 429 | 430 | */ 431 | 432 | #include 433 | 434 | #include 435 | 436 | #include "detail/config.hpp" 437 | #include "detail/invoke.hpp" 438 | #include "detail/lib.hpp" 439 | 440 | namespace slb { 441 | 442 | // libstdc++ did not mark `operator value_type` / `operator()` as `noexcept` 443 | // until version 8. 444 | #if __cpp_lib_integral_constant_callable && \ 445 | (!defined(__GLIBCXX__) || __has_include()) 446 | #define SLB_INTEGRAL_CONSTANT 2 // available / conforming 447 | #else 448 | #define SLB_INTEGRAL_CONSTANT 1 // available / non-conforming 449 | #endif 450 | 451 | // [meta.help], helper class 452 | 453 | #if SLB_INTEGRAL_CONSTANT == 2 // C++14 454 | using std::integral_constant; 455 | #else 456 | template 457 | struct integral_constant : std::integral_constant { 458 | using value_type = T; 459 | using type = integral_constant; 460 | 461 | constexpr operator value_type() const noexcept { return this->value; } 462 | constexpr value_type operator()() const noexcept { return this->value; } 463 | }; 464 | #endif 465 | 466 | template 467 | using bool_constant = slb::integral_constant; 468 | 469 | using true_type = slb::bool_constant; 470 | using false_type = slb::bool_constant; 471 | 472 | // [meta.unary.cat], primary type categories 473 | 474 | #if SLB_INTEGRAL_CONSTANT == 2 // C++14 475 | using std::is_void; 476 | using std::is_integral; 477 | using std::is_floating_point; 478 | using std::is_array; 479 | using std::is_pointer; 480 | using std::is_lvalue_reference; 481 | using std::is_rvalue_reference; 482 | using std::is_enum; 483 | using std::is_union; 484 | using std::is_class; 485 | #else 486 | template 487 | struct is_void : slb::bool_constant::value> {}; 488 | 489 | template 490 | struct is_integral : slb::bool_constant::value> {}; 491 | 492 | template 493 | struct is_floating_point 494 | : slb::bool_constant::value> {}; 495 | 496 | template 497 | struct is_array : slb::bool_constant::value> {}; 498 | 499 | template 500 | struct is_pointer : slb::bool_constant::value> {}; 501 | 502 | template 503 | struct is_lvalue_reference 504 | : slb::bool_constant::value> {}; 505 | 506 | template 507 | struct is_rvalue_reference 508 | : slb::bool_constant::value> {}; 509 | 510 | template 511 | struct is_enum : slb::bool_constant::value> {}; 512 | 513 | template 514 | struct is_union : slb::bool_constant::value> {}; 515 | 516 | template 517 | struct is_class : slb::bool_constant::value> {}; 518 | #endif 519 | 520 | #if __cpp_lib_is_null_pointer // C++14 521 | #if SLB_INTEGRAL_CONSTANT == 2 522 | using std::is_null_pointer; 523 | #else 524 | template 525 | struct is_null_pointer : slb::bool_constant::value> {}; 526 | #endif 527 | #else 528 | template 529 | struct is_null_pointer 530 | : slb::bool_constant< 531 | std::is_same::type>::value> {}; 533 | #endif 534 | 535 | // libstdc++ `is_function` does not recognize `noexcept` until version 7. 536 | #if !defined(__GLIBCXX__) || __has_include() // >= libstdc++-7 537 | #define SLB_IS_FUNCTION SLB_INTEGRAL_CONSTANT 538 | #else 539 | #define SLB_IS_FUNCTION 0 // not available 540 | #endif 541 | 542 | #if SLB_IS_FUNCTION == 2 543 | using std::is_member_object_pointer; 544 | using std::is_member_function_pointer; 545 | using std::is_function; 546 | #elif SLB_IS_FUNCTION == 1 547 | template 548 | struct is_member_object_pointer 549 | : slb::bool_constant::value> {}; 550 | 551 | template 552 | struct is_member_function_pointer 553 | : slb::bool_constant::value> {}; 554 | 555 | template 556 | struct is_function : slb::bool_constant::value> {}; 557 | #else 558 | template 559 | struct is_member_object_pointer : slb::false_type {}; 560 | 561 | template 562 | struct is_member_object_pointer 563 | : slb::bool_constant::value> {}; 564 | 565 | template 566 | struct is_member_function_pointer : slb::false_type {}; 567 | 568 | template 569 | struct is_member_function_pointer 570 | : slb::bool_constant::value> {}; 571 | 572 | template 573 | struct is_function : slb::bool_constant::value> {}; 574 | #endif 575 | 576 | // [meta.unary.comp], composite type categories 577 | 578 | #if SLB_INTEGRAL_CONSTANT == 2 // C++14 579 | using std::is_reference; 580 | using std::is_arithmetic; 581 | using std::is_fundamental; 582 | using std::is_scalar; 583 | using std::is_compound; 584 | using std::is_member_pointer; 585 | #else 586 | template 587 | struct is_reference : slb::bool_constant::value> {}; 588 | 589 | template 590 | struct is_arithmetic : slb::bool_constant::value> {}; 591 | 592 | template 593 | struct is_fundamental : slb::bool_constant::value> {}; 594 | 595 | template 596 | struct is_scalar : slb::bool_constant::value> {}; 597 | 598 | template 599 | struct is_compound : slb::bool_constant::value> {}; 600 | 601 | template 602 | struct is_member_pointer 603 | : slb::bool_constant::value> {}; 604 | #endif 605 | 606 | #if SLB_IS_FUNCTION == 2 607 | using std::is_object; 608 | #elif SLB_IS_FUNCTION == 1 609 | template 610 | struct is_object : slb::bool_constant::value> {}; 611 | #else 612 | template 613 | struct is_object : slb::bool_constant::value && 614 | !std::is_reference::value && 615 | !std::is_void::value> {}; 616 | #endif 617 | 618 | // [meta.unary.prop], type properties 619 | 620 | #if SLB_INTEGRAL_CONSTANT == 2 // C++14 621 | using std::is_const; 622 | using std::is_volatile; 623 | using std::is_trivial; 624 | using std::is_standard_layout; 625 | using std::is_empty; 626 | using std::is_polymorphic; 627 | using std::is_abstract; 628 | #else 629 | template 630 | struct is_const : slb::bool_constant::value> {}; 631 | 632 | template 633 | struct is_volatile : slb::bool_constant::value> {}; 634 | 635 | template 636 | struct is_trivial : slb::bool_constant::value> {}; 637 | 638 | template 639 | struct is_standard_layout 640 | : slb::bool_constant::value> {}; 641 | 642 | template 643 | struct is_empty : slb::bool_constant::value> {}; 644 | 645 | template 646 | struct is_polymorphic : slb::bool_constant::value> {}; 647 | 648 | template 649 | struct is_abstract : slb::bool_constant::value> {}; 650 | #endif 651 | 652 | #if !defined(__GLIBCXX__) || __has_include() // >= libstdc++-5 653 | #define SLB_TRIVIALITY_TRAITS SLB_INTEGRAL_CONSTANT 654 | #else 655 | #define SLB_TRIVIALITY_TRAITS 0 // not available 656 | #endif 657 | 658 | #if SLB_TRIVIALITY_TRAITS == 2 659 | using std::is_trivially_copyable; 660 | #elif SLB_TRIVIALITY_TRAITS == 1 661 | template 662 | struct is_trivially_copyable 663 | : slb::bool_constant::value> {}; 664 | #else 665 | template 666 | struct is_trivially_copyable { 667 | static_assert(detail::lib::always_false::value, 668 | "`is_trivially_copyable` is not available."); 669 | }; 670 | #endif 671 | 672 | #if __cpp_lib_is_final // C++14 673 | #if SLB_INTEGRAL_CONSTANT == 2 674 | using std::is_final; 675 | #else 676 | template 677 | struct is_final : slb::bool_constant::value> {}; 678 | #endif 679 | #elif __has_feature(is_final) || (__GNUC__ > 4) || \ 680 | ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) 681 | template 682 | struct is_final : slb::bool_constant<__is_final(T)> {}; 683 | #else 684 | template 685 | struct is_final { 686 | static_assert(detail::lib::always_false::value, 687 | "`is_final` is not available."); 688 | }; 689 | #endif 690 | 691 | #if __cpp_lib_is_aggregate // C++17 692 | #if SLB_INTEGRAL_CONSTANT == 2 693 | using std::is_aggregate; 694 | #else 695 | template 696 | struct is_aggregate : slb::bool_constant::value> {}; 697 | #endif 698 | #elif __has_feature(is_aggregate) || (__GNUC__ >= 7) 699 | template 700 | struct is_aggregate : slb::bool_constant<__is_aggregate(T)> {}; 701 | #else 702 | template 703 | struct is_aggregate { 704 | static_assert(detail::lib::always_false::value, 705 | "`is_aggregate` is not available."); 706 | }; 707 | #endif 708 | 709 | #if SLB_INTEGRAL_CONSTANT == 2 // C++14 710 | using std::is_signed; 711 | using std::is_unsigned; 712 | 713 | using std::is_destructible; 714 | using std::is_trivially_destructible; 715 | using std::is_nothrow_destructible; 716 | 717 | using std::is_assignable; 718 | using std::is_copy_assignable; 719 | using std::is_move_assignable; 720 | 721 | using std::is_nothrow_assignable; 722 | using std::is_nothrow_copy_assignable; 723 | using std::is_nothrow_move_assignable; 724 | #else 725 | template 726 | struct is_signed : slb::bool_constant::value> {}; 727 | 728 | template 729 | struct is_unsigned : slb::bool_constant::value> {}; 730 | 731 | template 732 | struct is_destructible : slb::bool_constant::value> {}; 733 | 734 | template 735 | struct is_trivially_destructible 736 | : slb::bool_constant::value> {}; 737 | 738 | template 739 | struct is_nothrow_destructible 740 | : slb::bool_constant::value> {}; 741 | 742 | template 743 | struct is_assignable : slb::bool_constant::value> {}; 744 | 745 | template 746 | struct is_copy_assignable 747 | : slb::bool_constant::value> {}; 748 | 749 | template 750 | struct is_move_assignable 751 | : slb::bool_constant::value> {}; 752 | 753 | template 754 | struct is_nothrow_assignable 755 | : slb::bool_constant::value> {}; 756 | 757 | template 758 | struct is_nothrow_copy_assignable 759 | : slb::bool_constant::value> {}; 760 | 761 | template 762 | struct is_nothrow_move_assignable 763 | : slb::bool_constant::value> {}; 764 | #endif 765 | 766 | // MSVC does not consider destructors in its `constructible` traits. 767 | #if !defined(_MSC_VER) || _MSC_VER >= 1910 768 | #define SLB_CONSTRUCTIBLE_TRAITS 2 // available / conforming 769 | #else 770 | #define SLB_CONSTRUCTIBLE_TRAITS 1 // available / non-conforming 771 | #endif 772 | 773 | #if SLB_INTEGRAL_CONSTANT == 2 && SLB_CONSTRUCTIBLE_TRAITS == 2 774 | using std::is_constructible; 775 | using std::is_default_constructible; 776 | using std::is_copy_constructible; 777 | using std::is_move_constructible; 778 | 779 | using std::is_nothrow_constructible; 780 | using std::is_nothrow_default_constructible; 781 | using std::is_nothrow_copy_constructible; 782 | using std::is_nothrow_move_constructible; 783 | #else 784 | template 785 | struct is_constructible 786 | : slb::bool_constant::value 787 | #if SLB_CONSTRUCTIBLE_TRAITS == 1 788 | && std::is_destructible::value 789 | #endif 790 | > { 791 | }; 792 | 793 | template 794 | struct is_default_constructible 795 | : slb::bool_constant::value 796 | #if SLB_CONSTRUCTIBLE_TRAITS == 1 797 | && std::is_destructible::value 798 | #endif 799 | > { 800 | }; 801 | 802 | template 803 | struct is_copy_constructible 804 | : slb::bool_constant::value 805 | #if SLB_CONSTRUCTIBLE_TRAITS == 1 806 | && std::is_destructible::value 807 | #endif 808 | > { 809 | }; 810 | 811 | template 812 | struct is_move_constructible 813 | : slb::bool_constant::value 814 | #if SLB_CONSTRUCTIBLE_TRAITS == 1 815 | && std::is_destructible::value 816 | #endif 817 | > { 818 | }; 819 | 820 | template 821 | struct is_nothrow_constructible 822 | : slb::bool_constant::value 823 | #if SLB_CONSTRUCTIBLE_TRAITS == 1 824 | && std::is_nothrow_destructible::value 825 | #endif 826 | > { 827 | }; 828 | 829 | template 830 | struct is_nothrow_default_constructible 831 | : slb::bool_constant::value 832 | #if SLB_CONSTRUCTIBLE_TRAITS == 1 833 | && std::is_nothrow_destructible::value 834 | #endif 835 | > { 836 | }; 837 | 838 | template 839 | struct is_nothrow_copy_constructible 840 | : slb::bool_constant::value 841 | #if SLB_CONSTRUCTIBLE_TRAITS == 1 842 | && std::is_nothrow_destructible::value 843 | #endif 844 | > { 845 | }; 846 | 847 | template 848 | struct is_nothrow_move_constructible 849 | : slb::bool_constant::value 850 | #if SLB_CONSTRUCTIBLE_TRAITS == 1 851 | && std::is_nothrow_destructible::value 852 | #endif 853 | > { 854 | }; 855 | #endif 856 | 857 | #if SLB_TRIVIALITY_TRAITS == 2 && SLB_CONSTRUCTIBLE_TRAITS == 2 858 | using std::is_trivially_constructible; 859 | using std::is_trivially_default_constructible; 860 | using std::is_trivially_copy_constructible; 861 | using std::is_trivially_move_constructible; 862 | #elif SLB_TRIVIALITY_TRAITS == 1 863 | template 864 | struct is_trivially_constructible 865 | : slb::bool_constant::value 866 | #if SLB_CONSTRUCTIBLE_TRAITS == 1 867 | && std::is_trivially_destructible::value 868 | #endif 869 | > { 870 | }; 871 | 872 | template 873 | struct is_trivially_default_constructible 874 | : slb::bool_constant::value 875 | #if SLB_CONSTRUCTIBLE_TRAITS == 1 876 | && std::is_trivially_destructible::value 877 | #endif 878 | > { 879 | }; 880 | 881 | template 882 | struct is_trivially_copy_constructible 883 | : slb::bool_constant::value 884 | #if SLB_CONSTRUCTIBLE_TRAITS == 1 885 | && std::is_trivially_destructible::value 886 | #endif 887 | > { 888 | }; 889 | 890 | template 891 | struct is_trivially_move_constructible 892 | : slb::bool_constant::value 893 | #if SLB_CONSTRUCTIBLE_TRAITS == 1 894 | && std::is_trivially_destructible::value 895 | #endif 896 | > { 897 | }; 898 | #else 899 | template 900 | struct is_trivially_constructible { 901 | static_assert(detail::lib::always_false::value, 902 | "`is_trivially_constructible` is not available."); 903 | }; 904 | 905 | namespace detail { 906 | // A defaulted default constructor for class `X` is defined as deleted if `X` is 907 | // a union that has a variant member with a non-trivial default constructor and 908 | // no variant member of `X` has a default member initializer. 909 | #ifdef _MSC_VER 910 | #pragma warning(push) 911 | #pragma warning(disable : 4624) // destructor was implicitly defined as deleted 912 | #endif 913 | template 914 | union trivial_default_constructor { 915 | T member; 916 | trivial_default_constructor() = default; 917 | }; 918 | #ifdef _MSC_VER 919 | #pragma warning(pop) 920 | #endif 921 | template 922 | using is_trivially_default_constructible = 923 | std::is_default_constructible>; 924 | } // namespace detail 925 | 926 | template 927 | struct is_trivially_default_constructible 928 | : slb::bool_constant< 929 | std::conditional::value, 930 | detail::is_trivially_default_constructible< 931 | typename std::remove_const::type>, 932 | std::false_type>::type::value 933 | #if SLB_CONSTRUCTIBLE_TRAITS == 1 934 | && std::is_trivially_destructible::value 935 | #endif 936 | > { 937 | }; 938 | 939 | namespace detail { 940 | // A defaulted copy/move constructor for a class `X` is defined as deleted if 941 | // `X` has a variant member whose corresponding constructor as selected by 942 | // overload resolution is non-trivial. 943 | #ifdef _MSC_VER 944 | #pragma warning(push) 945 | #pragma warning(disable : 4624) // destructor was implicitly defined as deleted 946 | #endif 947 | template 948 | union trivial_copy_constructor { 949 | T member; 950 | trivial_copy_constructor(trivial_copy_constructor const&) = default; 951 | }; 952 | #ifdef _MSC_VER 953 | #pragma warning(pop) 954 | #endif 955 | template 956 | using is_trivially_copy_constructible = 957 | std::is_copy_constructible>; 958 | } // namespace detail 959 | 960 | template 961 | struct is_trivially_copy_constructible 962 | : slb::bool_constant< 963 | std::conditional::value, 964 | detail::is_trivially_copy_constructible, 965 | std::false_type>::type::value 966 | #if SLB_CONSTRUCTIBLE_TRAITS == 1 967 | && std::is_trivially_destructible::value 968 | #endif 969 | > { 970 | }; 971 | 972 | template 973 | struct is_trivially_copy_constructible : slb::true_type {}; 974 | 975 | template 976 | struct is_trivially_copy_constructible : slb::false_type {}; 977 | 978 | namespace detail { 979 | // A defaulted copy/move constructor for a class `X` is defined as deleted if 980 | // `X` has a variant member whose corresponding constructor as selected by 981 | // overload resolution is non-trivial. A defaulted move constructor that is 982 | // defined as deleted is ignored by overload resolution. 983 | #ifdef _MSC_VER 984 | #pragma warning(push) 985 | #pragma warning(disable : 4624) // destructor was implicitly defined as deleted 986 | #endif 987 | template 988 | union trivial_move_constructor { 989 | T member; 990 | trivial_move_constructor(trivial_move_constructor&&) = default; 991 | trivial_move_constructor(trivial_move_constructor const&) = delete; 992 | }; 993 | #ifdef _MSC_VER 994 | #pragma warning(pop) 995 | #endif 996 | template 997 | using is_trivially_move_constructible = 998 | std::is_move_constructible>; 999 | } // namespace detail 1000 | 1001 | template 1002 | struct is_trivially_move_constructible 1003 | : slb::bool_constant< 1004 | std::conditional::value, 1005 | detail::is_trivially_move_constructible, 1006 | std::false_type>::type::value 1007 | #if SLB_CONSTRUCTIBLE_TRAITS == 1 1008 | && std::is_trivially_destructible::value 1009 | #endif 1010 | > { 1011 | }; 1012 | #endif 1013 | 1014 | template 1015 | struct is_trivially_move_constructible : slb::true_type {}; 1016 | 1017 | template 1018 | struct is_trivially_move_constructible : slb::true_type {}; 1019 | 1020 | #if SLB_TRIVIALITY_TRAITS == 2 1021 | using std::is_trivially_assignable; 1022 | using std::is_trivially_copy_assignable; 1023 | using std::is_trivially_move_assignable; 1024 | #elif SLB_TRIVIALITY_TRAITS == 1 1025 | template 1026 | struct is_trivially_assignable 1027 | : slb::bool_constant::value> {}; 1028 | 1029 | template 1030 | struct is_trivially_copy_assignable 1031 | : slb::bool_constant::value> {}; 1032 | 1033 | template 1034 | struct is_trivially_move_assignable 1035 | : slb::bool_constant::value> {}; 1036 | #else 1037 | template 1038 | struct is_trivially_assignable { 1039 | static_assert(detail::lib::always_false::value, 1040 | "`is_trivially_assignable` is not available."); 1041 | }; 1042 | 1043 | namespace detail { 1044 | // A defaulted copy/move assignment operator for class `X` is defined as deleted 1045 | // if `X` has a variant member with a non-trivial corresponding assignment 1046 | // operator and `X` is a union-like class. 1047 | #ifdef _MSC_VER 1048 | #pragma warning(push) 1049 | #pragma warning(disable : 4624) // destructor was implicitly defined as deleted 1050 | #endif 1051 | template 1052 | union trivial_copy_assign { 1053 | T member; 1054 | trivial_copy_assign& operator=(trivial_copy_assign const&) = default; 1055 | }; 1056 | #ifdef _MSC_VER 1057 | #pragma warning(pop) 1058 | #endif 1059 | template 1060 | using is_trivially_copy_assignable = 1061 | std::is_copy_assignable>; 1062 | } // namespace detail 1063 | 1064 | template 1065 | struct is_trivially_copy_assignable 1066 | : slb::bool_constant< 1067 | std::conditional::value, 1068 | detail::is_trivially_copy_assignable< 1069 | typename std::remove_reference::type>, 1070 | std::false_type>::type::value> {}; 1071 | 1072 | namespace detail { 1073 | // A defaulted copy/move assignment operator for class `X` is defined as deleted 1074 | // if `X` has a variant member with a non-trivial corresponding assignment 1075 | // operator and `X` is a union-like class. A defaulted move assignment operator 1076 | // that is defined as deleted is ignored by overload resolution. 1077 | #ifdef _MSC_VER 1078 | #pragma warning(push) 1079 | #pragma warning(disable : 4624) // destructor was implicitly defined as deleted 1080 | #endif 1081 | template 1082 | union trivial_move_assign { 1083 | T member; 1084 | trivial_move_assign& operator=(trivial_move_assign&&) = default; 1085 | trivial_move_assign& operator=(trivial_move_assign const&) = delete; 1086 | }; 1087 | #ifdef _MSC_VER 1088 | #pragma warning(pop) 1089 | #endif 1090 | template 1091 | using is_trivially_move_assignable = 1092 | std::is_move_assignable>; 1093 | } // namespace detail 1094 | 1095 | template 1096 | struct is_trivially_move_assignable 1097 | : slb::bool_constant< 1098 | std::conditional::value, 1099 | detail::is_trivially_move_assignable< 1100 | typename std::remove_reference::type>, 1101 | std::false_type>::type::value> {}; 1102 | #endif 1103 | 1104 | #if __cpp_lib_is_swappable // C++17 1105 | #if SLB_INTEGRAL_CONSTANT == 2 1106 | using std::is_swappable_with; 1107 | using std::is_swappable; 1108 | using std::is_nothrow_swappable_with; 1109 | using std::is_nothrow_swappable; 1110 | #else 1111 | template 1112 | struct is_swappable_with 1113 | : slb::bool_constant::value> {}; 1114 | template 1115 | struct is_swappable : slb::bool_constant::value> {}; 1116 | template 1117 | struct is_nothrow_swappable_with 1118 | : slb::bool_constant::value> {}; 1119 | template 1120 | struct is_nothrow_swappable 1121 | : slb::bool_constant::value> {}; 1122 | #endif 1123 | #else 1124 | // TODO 1125 | // template struct is_swappable_with; 1126 | // template struct is_swappable; 1127 | // template struct is_nothrow_swappable_with; 1128 | // template struct is_nothrow_swappable; 1129 | #endif 1130 | 1131 | #if SLB_INTEGRAL_CONSTANT == 2 // C++14 1132 | using std::has_virtual_destructor; 1133 | #else 1134 | template 1135 | struct has_virtual_destructor 1136 | : slb::bool_constant::value> {}; 1137 | #endif 1138 | 1139 | #if __cpp_lib_has_unique_object_representations // C++17 1140 | #if SLB_INTEGRAL_CONSTANT == 2 1141 | using std::has_unique_object_representations; 1142 | #else 1143 | template 1144 | struct has_unique_object_representations 1145 | : slb::bool_constant::value> {}; 1146 | #endif 1147 | #elif __has_feature(has_unique_object_representations) || (__GNUC__ >= 7) 1148 | template 1149 | struct has_unique_object_representations 1150 | : slb::bool_constant<__has_unique_object_representations(T)> {}; 1151 | #else 1152 | template 1153 | struct has_unique_object_representations { 1154 | static_assert(detail::lib::always_false::value, 1155 | "`has_unique_object_representations` is not available."); 1156 | }; 1157 | #endif 1158 | 1159 | // [meta.unary.prop.query] type property queries 1160 | 1161 | #if SLB_INTEGRAL_CONSTANT == 2 // C++14 1162 | using std::alignment_of; 1163 | using std::rank; 1164 | using std::extent; 1165 | #else 1166 | template 1167 | struct alignment_of 1168 | : slb::integral_constant::value> {}; 1169 | 1170 | template 1171 | struct rank : slb::integral_constant::value> {}; 1172 | 1173 | template 1174 | struct extent : slb::integral_constant::value> { 1175 | }; 1176 | #endif 1177 | 1178 | // [meta.rel], type relations 1179 | 1180 | #if SLB_INTEGRAL_CONSTANT == 2 // C++14 1181 | using std::is_same; 1182 | using std::is_base_of; 1183 | using std::is_convertible; 1184 | #else 1185 | template 1186 | struct is_same : slb::bool_constant::value> {}; 1187 | 1188 | template 1189 | struct is_base_of : slb::bool_constant::value> { 1190 | }; 1191 | 1192 | template 1193 | struct is_convertible 1194 | : slb::bool_constant::value> {}; 1195 | #endif 1196 | 1197 | // We only enable the C++17 implementation under C++2a here to account for 1198 | // P0704: "Fixing const-qualified pointers to members". 1199 | 1200 | #if __cpp_lib_is_invocable /* C++17 */ && __cplusplus > 201703L /* C++2a */ 1201 | #if SLB_INTEGRAL_CONSTANT == 2 1202 | using std::is_invocable; 1203 | using std::is_invocable_r; 1204 | using std::is_nothrow_invocable; 1205 | using std::is_nothrow_invocable_r; 1206 | #else 1207 | template 1208 | struct is_invocable : slb::bool_constant::value> { 1209 | }; 1210 | 1211 | template 1212 | struct is_invocable_r 1213 | : slb::bool_constant::value> {}; 1214 | 1215 | template 1216 | struct is_nothrow_invocable 1217 | : slb::bool_constant::value> {}; 1218 | 1219 | template 1220 | struct is_nothrow_invocable_r 1221 | : slb::bool_constant::value> {}; 1222 | #endif 1223 | #else 1224 | namespace detail { 1225 | 1226 | template 1227 | struct is_invocable_impl { 1228 | static constexpr bool value = false; 1229 | static constexpr bool nothrow = false; 1230 | }; 1231 | 1232 | template 1233 | struct is_invocable_impl(), std::declval()...)))> { 1236 | static constexpr bool value = true; 1237 | static constexpr bool nothrow = 1238 | noexcept(detail::invoke(std::declval(), std::declval()...)); 1239 | }; 1240 | 1241 | template 1242 | struct is_invocable_r_impl { 1243 | static constexpr bool value = false; 1244 | static constexpr bool nothrow = false; 1245 | }; 1246 | 1247 | template 1248 | struct is_invocable_r_impl( 1251 | std::declval(), std::declval()...)))> { 1252 | static constexpr bool value = true; 1253 | static constexpr bool nothrow = 1254 | noexcept(detail::invoke_r(std::declval(), std::declval()...)); 1255 | }; 1256 | 1257 | } // namespace detail 1258 | 1259 | template 1260 | struct is_invocable 1261 | : slb::bool_constant::value> { 1262 | }; 1263 | 1264 | template 1265 | struct is_invocable_r 1266 | : slb::bool_constant< 1267 | detail::is_invocable_r_impl::value> {}; 1268 | 1269 | template 1270 | struct is_nothrow_invocable 1271 | : slb::bool_constant< 1272 | detail::is_invocable_impl::nothrow> {}; 1273 | 1274 | template 1275 | struct is_nothrow_invocable_r 1276 | : slb::bool_constant< 1277 | detail::is_invocable_r_impl::nothrow> {}; 1278 | #endif 1279 | 1280 | // [meta.trans.cv], const-volatile modifications 1281 | 1282 | using std::remove_const; 1283 | using std::remove_volatile; 1284 | using std::remove_cv; 1285 | using std::add_const; 1286 | using std::add_volatile; 1287 | using std::add_cv; 1288 | 1289 | template 1290 | using remove_const_t = typename slb::remove_const::type; 1291 | 1292 | template 1293 | using remove_volatile_t = typename slb::remove_volatile::type; 1294 | 1295 | template 1296 | using remove_cv_t = typename slb::remove_cv::type; 1297 | 1298 | template 1299 | using add_const_t = typename slb::add_const::type; 1300 | 1301 | template 1302 | using add_volatile_t = typename slb::add_volatile::type; 1303 | 1304 | template 1305 | using add_cv_t = typename slb::add_cv::type; 1306 | 1307 | // [meta.trans.ref], reference modifications 1308 | 1309 | using std::remove_reference; 1310 | using std::add_lvalue_reference; 1311 | using std::add_rvalue_reference; 1312 | 1313 | template 1314 | using remove_reference_t = typename slb::remove_reference::type; 1315 | 1316 | template 1317 | using add_lvalue_reference_t = typename slb::add_lvalue_reference::type; 1318 | 1319 | template 1320 | using add_rvalue_reference_t = typename slb::add_rvalue_reference::type; 1321 | 1322 | // [meta.trans.sign], sign modifications 1323 | 1324 | using std::make_signed; 1325 | using std::make_unsigned; 1326 | 1327 | template 1328 | using make_signed_t = typename slb::make_signed::type; 1329 | 1330 | template 1331 | using make_unsigned_t = typename slb::make_unsigned::type; 1332 | 1333 | // [meta.trans.arr], array modifications 1334 | 1335 | using std::remove_extent; 1336 | using std::remove_all_extents; 1337 | 1338 | template 1339 | using remove_extent_t = typename slb::remove_extent::type; 1340 | 1341 | template 1342 | using remove_all_extents_t = typename slb::remove_all_extents::type; 1343 | 1344 | // [meta.trans.ptr], pointer modifications 1345 | 1346 | using std::remove_pointer; 1347 | using std::add_pointer; 1348 | 1349 | template 1350 | using remove_pointer_t = typename slb::remove_pointer::type; 1351 | 1352 | template 1353 | using add_pointer_t = typename slb::add_pointer::type; 1354 | 1355 | // [meta.trans.other], other transformations 1356 | 1357 | template 1358 | struct type_identity { 1359 | using type = T; 1360 | }; 1361 | 1362 | using std::aligned_storage; 1363 | 1364 | // libstdc++ did not provide `aligned_union` until version 5. 1365 | // libc++ does not provide an out-of-class definition for `alignment_value`. 1366 | #if !defined(__GLIBCXX__) || __has_include() // >= libstdc++-5 1367 | #if !defined(_LIBCPP_VERSION) 1368 | #define SLB_ALIGNED_UNION 2 // available / conforming 1369 | #else 1370 | #define SLB_ALIGNED_UNION 1 // available / non-conforming 1371 | #endif 1372 | #else 1373 | #define SLB_ALIGNED_UNION 0 // not available 1374 | #endif 1375 | 1376 | #if SLB_ALIGNED_UNION == 2 1377 | using std::aligned_union; 1378 | #else 1379 | #if SLB_ALIGNED_UNION == 1 1380 | template 1381 | struct aligned_union : std::aligned_union { 1382 | static constexpr std::size_t alignment_value = 1383 | std::aligned_union::alignment_value; 1384 | }; 1385 | #else 1386 | namespace detail { 1387 | template 1388 | struct static_max; 1389 | 1390 | template 1391 | struct static_max { 1392 | static constexpr std::size_t value = V; 1393 | }; 1394 | 1395 | template 1396 | struct static_max : static_max<(V0 < V1 ? V1 : V0), Vs...> {}; 1397 | } // namespace detail 1398 | 1399 | template 1400 | struct aligned_union { 1401 | static_assert(sizeof...(Ts) > 0, "At least one type shall be provided."); 1402 | 1403 | static constexpr std::size_t alignment_value = 1404 | detail::static_max::value; 1405 | 1406 | using type = typename std::aligned_storage< 1407 | detail::static_max::value, 1408 | alignment_value>::type; 1409 | }; 1410 | #endif 1411 | 1412 | template 1413 | constexpr std::size_t aligned_union::alignment_value; 1414 | #endif 1415 | 1416 | template 1417 | struct remove_cvref { 1418 | using type = 1419 | typename std::remove_cv::type>::type; 1420 | }; 1421 | 1422 | using std::decay; 1423 | using std::enable_if; 1424 | using std::conditional; 1425 | 1426 | // TODO: C++14 (SFINAE) / C++17 (recursive commutative `std::decay_t`) 1427 | using std::common_type; 1428 | 1429 | using std::underlying_type; 1430 | 1431 | namespace detail { 1432 | 1433 | template 1434 | struct default_alignment; 1435 | 1436 | template 1437 | struct default_alignment> 1438 | : slb::integral_constant {}; 1439 | 1440 | } // namespace detail 1441 | 1442 | template 1443 | using type_identity_t = typename slb::type_identity::type; 1444 | 1445 | template >::value> 1448 | using aligned_storage_t = typename slb::aligned_storage::type; 1449 | 1450 | template 1451 | using aligned_union_t = typename slb::aligned_union::type; 1452 | 1453 | template 1454 | using remove_cvref_t = typename slb::remove_cvref::type; 1455 | 1456 | template 1457 | using decay_t = typename slb::decay::type; 1458 | 1459 | template 1460 | using enable_if_t = typename slb::enable_if::type; 1461 | 1462 | template 1463 | using conditional_t = typename slb::conditional::type; 1464 | 1465 | template 1466 | using common_type_t = typename slb::common_type::type; 1467 | 1468 | template 1469 | using underlying_type_t = typename slb::underlying_type::type; 1470 | 1471 | // We only enable the C++17 implementation under C++2a here to account for 1472 | // P0704: "Fixing const-qualified pointers to members". 1473 | 1474 | #if __cpp_lib_is_invocable /* C++17 */ && __cplusplus > 201703L /* C++2a */ 1475 | using std::invoke_result; 1476 | using std::invoke_result_t; 1477 | #else 1478 | namespace detail { 1479 | 1480 | template 1481 | struct invoke_result_impl {}; 1482 | 1483 | template 1484 | struct invoke_result_impl(), std::declval()...))> { 1487 | using type = 1488 | decltype(detail::invoke(std::declval(), std::declval()...)); 1489 | }; 1490 | 1491 | } // namespace detail 1492 | 1493 | template 1494 | struct invoke_result : detail::invoke_result_impl {}; 1495 | 1496 | template 1497 | using invoke_result_t = typename slb::invoke_result::type; 1498 | #endif 1499 | 1500 | // gcc did not implement CWG1558: "Unused arguments in alias template 1501 | // specializations" until version 5. 1502 | #if !defined(__GNUC__) || __GNUC__ >= 5 1503 | template 1504 | using void_t = void; 1505 | #else 1506 | namespace detail { 1507 | template 1508 | struct dependent_void { 1509 | using type = void; 1510 | }; 1511 | } // namespace detail 1512 | 1513 | template 1514 | using void_t = typename detail::dependent_void::type; 1515 | #endif 1516 | 1517 | // [meta.logical], logical operator traits 1518 | 1519 | // We don't enable the C++17 implementations via `__cpp_lib_logical_traits` 1520 | // here since none of the implementations (i.e., libstdc++, libc++, MSVC) 1521 | // are currently strictly conforming. 1522 | 1523 | template 1524 | struct conjunction : slb::true_type {}; 1525 | 1526 | template 1527 | struct conjunction : B {}; 1528 | 1529 | // We deviate slightly here from the standard by performing a `static_assert` to 1530 | // `bool` rather than a C-style cast. Reconsider this if it turns out to matter. 1531 | template 1532 | struct conjunction 1533 | : slb::conditional_t(B::value), conjunction, B> { 1534 | static_assert(std::is_convertible::value, 1535 | "Member `value` shall be convertible to `bool`."); 1536 | }; 1537 | 1538 | template 1539 | struct disjunction : slb::false_type {}; 1540 | 1541 | template 1542 | struct disjunction : B {}; 1543 | 1544 | // We deviate slightly here from the standard by performing a `static_assert` to 1545 | // `bool` rather than a C-style cast. Reconsider this if it turns out to matter. 1546 | template 1547 | struct disjunction 1548 | : slb::conditional_t(B::value), B, disjunction> { 1549 | static_assert(std::is_convertible::value, 1550 | "Member `value` shall be convertible to `bool`."); 1551 | }; 1552 | 1553 | template 1554 | struct negation : slb::bool_constant(B::value)> {}; 1555 | 1556 | // [meta.endian], endian 1557 | 1558 | enum class endian { 1559 | #ifdef _WIN32 1560 | little = 0, 1561 | big = 1, 1562 | native = little 1563 | #else 1564 | little = __ORDER_LITTLE_ENDIAN__, 1565 | big = __ORDER_BIG_ENDIAN__, 1566 | native = __BYTE_ORDER__ 1567 | #endif 1568 | }; 1569 | 1570 | #if SLB_HAS_CXX14_VARIABLE_TEMPLATES 1571 | 1572 | // [meta.unary.cat], primary type categories 1573 | 1574 | template 1575 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_void_v = slb::is_void::value; 1576 | 1577 | template 1578 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_null_pointer_v = 1579 | slb::is_null_pointer::value; 1580 | 1581 | template 1582 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_integral_v = 1583 | slb::is_integral::value; 1584 | 1585 | template 1586 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_floating_point_v = 1587 | slb::is_floating_point::value; 1588 | 1589 | template 1590 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_array_v = slb::is_array::value; 1591 | 1592 | template 1593 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_pointer_v = 1594 | slb::is_pointer::value; 1595 | 1596 | template 1597 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_lvalue_reference_v = 1598 | slb::is_lvalue_reference::value; 1599 | 1600 | template 1601 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_rvalue_reference_v = 1602 | slb::is_rvalue_reference::value; 1603 | 1604 | template 1605 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_member_object_pointer_v = 1606 | slb::is_member_object_pointer::value; 1607 | 1608 | template 1609 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_member_function_pointer_v = 1610 | slb::is_member_function_pointer::value; 1611 | 1612 | template 1613 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_enum_v = slb::is_enum::value; 1614 | 1615 | template 1616 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_union_v = slb::is_union::value; 1617 | 1618 | template 1619 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_class_v = slb::is_class::value; 1620 | 1621 | template 1622 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_function_v = 1623 | slb::is_function::value; 1624 | 1625 | // [meta.unary.comp], composite type categories 1626 | 1627 | template 1628 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_reference_v = 1629 | slb::is_reference::value; 1630 | 1631 | template 1632 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_arithmetic_v = 1633 | slb::is_arithmetic::value; 1634 | 1635 | template 1636 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_fundamental_v = 1637 | slb::is_fundamental::value; 1638 | 1639 | template 1640 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_object_v = slb::is_object::value; 1641 | 1642 | template 1643 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_scalar_v = slb::is_scalar::value; 1644 | 1645 | template 1646 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_compound_v = 1647 | slb::is_compound::value; 1648 | 1649 | template 1650 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_member_pointer_v = 1651 | slb::is_member_pointer::value; 1652 | 1653 | // [meta.unary.prop], type properties 1654 | template 1655 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_const_v = slb::is_const::value; 1656 | 1657 | template 1658 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_volatile_v = 1659 | slb::is_volatile::value; 1660 | 1661 | template 1662 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_trivial_v = 1663 | slb::is_trivial::value; 1664 | 1665 | template 1666 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_trivially_copyable_v = 1667 | slb::is_trivially_copyable::value; 1668 | 1669 | template 1670 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_standard_layout_v = 1671 | slb::is_standard_layout::value; 1672 | 1673 | template 1674 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_empty_v = slb::is_empty::value; 1675 | 1676 | template 1677 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_polymorphic_v = 1678 | slb::is_polymorphic::value; 1679 | 1680 | template 1681 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_abstract_v = 1682 | slb::is_abstract::value; 1683 | 1684 | template 1685 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_final_v = slb::is_final::value; 1686 | 1687 | template 1688 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_aggregate_v = 1689 | slb::is_aggregate::value; 1690 | 1691 | template 1692 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_signed_v = slb::is_signed::value; 1693 | 1694 | template 1695 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_unsigned_v = 1696 | slb::is_unsigned::value; 1697 | 1698 | template 1699 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_constructible_v = 1700 | slb::is_constructible::value; 1701 | 1702 | template 1703 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_default_constructible_v = 1704 | slb::is_default_constructible::value; 1705 | 1706 | template 1707 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_copy_constructible_v = 1708 | slb::is_copy_constructible::value; 1709 | 1710 | template 1711 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_move_constructible_v = 1712 | slb::is_move_constructible::value; 1713 | 1714 | template 1715 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_assignable_v = 1716 | slb::is_assignable::value; 1717 | 1718 | template 1719 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_copy_assignable_v = 1720 | slb::is_copy_assignable::value; 1721 | 1722 | template 1723 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_move_assignable_v = 1724 | slb::is_move_assignable::value; 1725 | 1726 | // TODO 1727 | // template 1728 | // SLB_CXX17_INLINE_VARIABLE constexpr bool is_swappable_with_v = 1729 | // slb::is_swappable_with::value; 1730 | // 1731 | // template 1732 | // SLB_CXX17_INLINE_VARIABLE constexpr bool is_swappable_v = 1733 | // slb::is_swappable::value; 1734 | 1735 | template 1736 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_destructible_v = 1737 | slb::is_destructible::value; 1738 | 1739 | template 1740 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_trivially_constructible_v = 1741 | slb::is_trivially_constructible::value; 1742 | 1743 | template 1744 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_trivially_default_constructible_v = 1745 | slb::is_trivially_default_constructible::value; 1746 | 1747 | template 1748 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_trivially_copy_constructible_v = 1749 | slb::is_trivially_copy_constructible::value; 1750 | 1751 | template 1752 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_trivially_move_constructible_v = 1753 | slb::is_trivially_move_constructible::value; 1754 | 1755 | template 1756 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_trivially_assignable_v = 1757 | slb::is_trivially_assignable::value; 1758 | 1759 | template 1760 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_trivially_copy_assignable_v = 1761 | slb::is_trivially_copy_assignable::value; 1762 | 1763 | template 1764 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_trivially_move_assignable_v = 1765 | slb::is_trivially_move_assignable::value; 1766 | 1767 | template 1768 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_trivially_destructible_v = 1769 | slb::is_trivially_destructible::value; 1770 | 1771 | template 1772 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_nothrow_constructible_v = 1773 | slb::is_nothrow_constructible::value; 1774 | 1775 | template 1776 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_nothrow_default_constructible_v = 1777 | slb::is_nothrow_default_constructible::value; 1778 | 1779 | template 1780 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_nothrow_copy_constructible_v = 1781 | slb::is_nothrow_copy_constructible::value; 1782 | 1783 | template 1784 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_nothrow_move_constructible_v = 1785 | slb::is_nothrow_move_constructible::value; 1786 | 1787 | template 1788 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_nothrow_assignable_v = 1789 | slb::is_nothrow_assignable::value; 1790 | 1791 | template 1792 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_nothrow_copy_assignable_v = 1793 | slb::is_nothrow_copy_assignable::value; 1794 | 1795 | template 1796 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_nothrow_move_assignable_v = 1797 | slb::is_nothrow_move_assignable::value; 1798 | 1799 | // TODO 1800 | // template 1801 | // SLB_CXX17_INLINE_VARIABLE constexpr bool is_nothrow_swappable_with_v = 1802 | // slb::is_nothrow_swappable_with::value; 1803 | // 1804 | // template 1805 | // SLB_CXX17_INLINE_VARIABLE constexpr bool is_nothrow_swappable_v = 1806 | // slb::is_nothrow_swappable::value; 1807 | 1808 | template 1809 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_nothrow_destructible_v = 1810 | slb::is_nothrow_destructible::value; 1811 | 1812 | template 1813 | SLB_CXX17_INLINE_VARIABLE constexpr bool has_virtual_destructor_v = 1814 | slb::has_virtual_destructor::value; 1815 | 1816 | template 1817 | SLB_CXX17_INLINE_VARIABLE constexpr bool has_unique_object_representations_v = 1818 | slb::has_unique_object_representations::value; 1819 | 1820 | // [meta.unary.prop.query], type property queries 1821 | template 1822 | SLB_CXX17_INLINE_VARIABLE constexpr std::size_t alignment_of_v = 1823 | slb::alignment_of::value; 1824 | 1825 | template 1826 | SLB_CXX17_INLINE_VARIABLE constexpr std::size_t rank_v = slb::rank::value; 1827 | 1828 | template 1829 | SLB_CXX17_INLINE_VARIABLE constexpr std::size_t extent_v = 1830 | slb::extent::value; 1831 | 1832 | // [meta.rel], type relations 1833 | 1834 | template 1835 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_same_v = slb::is_same::value; 1836 | 1837 | template 1838 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_base_of_v = 1839 | slb::is_base_of::value; 1840 | 1841 | template 1842 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_convertible_v = 1843 | slb::is_convertible::value; 1844 | 1845 | template 1846 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_invocable_v = 1847 | slb::is_invocable::value; 1848 | 1849 | template 1850 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_invocable_r_v = 1851 | slb::is_invocable_r::value; 1852 | 1853 | template 1854 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_nothrow_invocable_v = 1855 | slb::is_nothrow_invocable::value; 1856 | 1857 | template 1858 | SLB_CXX17_INLINE_VARIABLE constexpr bool is_nothrow_invocable_r_v = 1859 | slb::is_nothrow_invocable_r::value; 1860 | 1861 | // [meta.logical], logical operator traits 1862 | 1863 | template 1864 | SLB_CXX17_INLINE_VARIABLE constexpr bool conjunction_v = 1865 | slb::conjunction::value; 1866 | 1867 | template 1868 | SLB_CXX17_INLINE_VARIABLE constexpr bool disjunction_v = 1869 | slb::disjunction::value; 1870 | 1871 | template 1872 | SLB_CXX17_INLINE_VARIABLE constexpr bool negation_v = slb::negation::value; 1873 | 1874 | #endif 1875 | 1876 | } // namespace slb 1877 | 1878 | #endif // SLB_TYPE_TRAITS_HPP 1879 | -------------------------------------------------------------------------------- /include/slb/utility.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | SLB.Utility 3 | 4 | Copyright Michael Park, 2017 5 | Copyright Agustin Berge, 2017 6 | 7 | Distributed under the Boost Software License, Version 1.0. 8 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 9 | */ 10 | 11 | #ifndef SLB_UTILITY_HPP 12 | #define SLB_UTILITY_HPP 13 | 14 | /* 15 | 16 | Header synopsis [utility.syn] 17 | 18 | #include // see [initializer_list.syn] 19 | 20 | namespace std { 21 | // [utility.swap], swap 22 | template 23 | void swap(T& a, T& b) noexcept(see below); 24 | template 25 | void swap(T (&a)[N], T (&b)[N]) noexcept(is_nothrow_swappable_v); 26 | 27 | // [utility.exchange], exchange 28 | template 29 | constexpr T exchange(T& obj, U&& new_val); 30 | 31 | // [forward], forward/move 32 | template 33 | constexpr T&& forward(remove_reference_t& t) noexcept; 34 | template 35 | constexpr T&& forward(remove_reference_t&& t) noexcept; 36 | template 37 | constexpr remove_reference_t&& move(T&&) noexcept; 38 | template 39 | constexpr conditional_t< 40 | !is_nothrow_move_constructible_v && is_copy_constructible_v, 41 | const T&, 42 | T&&> 43 | move_if_noexcept(T& x) noexcept; 44 | 45 | // [utility.as_const], as_const 46 | template 47 | constexpr add_const_t& as_const(T& t) noexcept; 48 | template 49 | void as_const(const T&&) = delete; 50 | 51 | // [declval], declval 52 | template 53 | add_rvalue_reference_t declval() noexcept; // as unevaluated operand 54 | 55 | // [intseq], Compile-time integer sequences 56 | template 57 | struct integer_sequence; 58 | template 59 | using index_sequence = integer_sequence; 60 | 61 | template 62 | using make_integer_sequence = integer_sequence; 63 | template 64 | using make_index_sequence = make_integer_sequence; 65 | 66 | template 67 | using index_sequence_for = make_index_sequence; 68 | 69 | // [pairs], class template pair 70 | template 71 | struct pair; 72 | 73 | // [pairs.spec], pair specialized algorithms 74 | template 75 | constexpr bool operator==(const pair&, const pair&); 76 | template 77 | constexpr bool operator< (const pair&, const pair&); 78 | template 79 | constexpr bool operator!=(const pair&, const pair&); 80 | template 81 | constexpr bool operator> (const pair&, const pair&); 82 | template 83 | constexpr bool operator>=(const pair&, const pair&); 84 | template 85 | constexpr bool operator<=(const pair&, const pair&); 86 | 87 | template 88 | void swap(pair& x, pair& y) noexcept(noexcept(x.swap(y))); 89 | 90 | template 91 | constexpr see below make_pair(T1&&, T2&&); 92 | 93 | // [pair.astuple], tuple-like access to pair 94 | template class tuple_size; 95 | template class tuple_element; 96 | 97 | template struct tuple_size>; 98 | template struct tuple_element>; 99 | 100 | template 101 | constexpr tuple_element_t>& get(pair&) noexcept; 102 | template 103 | constexpr tuple_element_t>&& get(pair&&) noexcept; 104 | template 105 | constexpr const tuple_element_t>& 106 | get(const pair&) noexcept; 107 | template 108 | constexpr const tuple_element_t>&& 109 | get(const pair&&) noexcept; 110 | template 111 | constexpr T1& get(pair& p) noexcept; 112 | template 113 | constexpr const T1& get(const pair& p) noexcept; 114 | template 115 | constexpr T1&& get(pair&& p) noexcept; 116 | template 117 | constexpr const T1&& get(const pair&& p) noexcept; 118 | template 119 | constexpr T2& get(pair& p) noexcept; 120 | template 121 | constexpr const T2& get(const pair& p) noexcept; 122 | template 123 | constexpr T2&& get(pair&& p) noexcept; 124 | template 125 | constexpr const T2&& get(const pair&& p) noexcept; 126 | 127 | // [pair.piecewise], pair piecewise construction 128 | struct piecewise_construct_t { 129 | explicit piecewise_construct_t() = default; 130 | }; 131 | inline constexpr piecewise_construct_t piecewise_construct{}; 132 | template class tuple; // defined in 133 | 134 | // in-place construction 135 | struct in_place_t { 136 | explicit in_place_t() = default; 137 | }; 138 | inline constexpr in_place_t in_place{}; 139 | template 140 | struct in_place_type_t { 141 | explicit in_place_type_t() = default; 142 | }; 143 | template inline constexpr in_place_type_t in_place_type{}; 144 | template 145 | struct in_place_index_t { 146 | explicit in_place_index_t() = default; 147 | }; 148 | template inline constexpr in_place_index_t in_place_index{}; 149 | } 150 | 151 | */ 152 | 153 | #include 154 | 155 | #include 156 | #include 157 | #include 158 | 159 | #include "detail/config.hpp" 160 | #include "detail/lib.hpp" 161 | 162 | namespace slb { 163 | 164 | // [utility.exchange], exchange 165 | 166 | template 167 | SLB_CXX14_CONSTEXPR T exchange(T& obj, U&& new_val) { 168 | T old_val = std::move(obj); 169 | obj = std::forward(new_val); 170 | return old_val; 171 | } 172 | 173 | // [forward], forward/move 174 | 175 | #if !defined(_LIBCPP_STD_VER) || \ 176 | (_LIBCPP_STD_VER > 11 && !defined(_LIBCPP_HAS_NO_CXX14_CONSTEXPR)) 177 | #define SLB_FORWARD_AND_MOVE 2 // available / conforming 178 | #define SLB_MOVE_IF_NOEXCEPT 2 // available / conforming 179 | #else 180 | #if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION >= 4000 181 | #define SLB_FORWARD_AND_MOVE 2 // available / conforming 182 | #else 183 | #define SLB_FORWARD_AND_MOVE 1 // available / non-conforming 184 | #endif 185 | #define SLB_MOVE_IF_NOEXCEPT 1 // available / non-conforming 186 | #endif 187 | 188 | #if SLB_FORWARD_AND_MOVE == 2 189 | using std::forward; 190 | using std::move; 191 | #else 192 | template 193 | constexpr T&& forward(typename std::remove_reference::type& t) noexcept { 194 | return static_cast(t); 195 | } 196 | 197 | template 198 | constexpr T&& forward(typename std::remove_reference::type&& t) noexcept { 199 | static_assert(!std::is_lvalue_reference::value, 200 | "can not forward an rvalue as an lvalue"); 201 | return static_cast(t); 202 | } 203 | 204 | template 205 | constexpr typename std::remove_reference::type&& move(T&& t) noexcept { 206 | return static_cast::type&&>(t); 207 | } 208 | #endif 209 | 210 | #if SLB_MOVE_IF_NOEXCEPT == 2 211 | using std::move_if_noexcept; 212 | #else 213 | template 214 | constexpr 215 | typename std::conditional<(!std::is_nothrow_move_constructible::value && 216 | std::is_copy_constructible::value), 217 | T const&, 218 | T&&>::type 219 | move_if_noexcept(T& x) noexcept { 220 | return slb::move(x); 221 | } 222 | #endif 223 | 224 | // [utility.as_const], as_const 225 | 226 | template 227 | constexpr typename std::add_const::type& as_const(T& t) noexcept { 228 | return t; 229 | } 230 | 231 | template 232 | void as_const(T const&&) = delete; 233 | 234 | // [intseq], Compile-time integer sequences 235 | 236 | #if __cpp_lib_integer_sequence || \ 237 | (_LIBCPP_VERSION >= 1101 && _LIBCPP_STD_VER > 11) || defined(_MSC_VER) 238 | // libstdc++ did not mark `size()` as `noexcept` until version 8. 239 | #if defined(__GLIBCXX__) && __has_include() 240 | #define SLB_INTEGER_SEQUENCE 2 // available / conforming 241 | #else 242 | #define SLB_INTEGER_SEQUENCE 1 // available / non-conforming 243 | #endif 244 | #else 245 | #define SLB_INTEGER_SEQUENCE 0 // not available 246 | #endif 247 | 248 | #if SLB_INTEGER_SEQUENCE == 2 249 | using std::integer_sequence; 250 | #else 251 | template 252 | struct integer_sequence 253 | #if SLB_INTEGER_SEQUENCE == 1 254 | : std::integer_sequence 255 | #endif 256 | { 257 | static_assert(std::is_integral::value, "`T` shall be an integer type."); 258 | using value_type = T; 259 | static constexpr std::size_t size() noexcept { return sizeof...(Is); } 260 | }; 261 | #endif 262 | 263 | template 264 | using index_sequence = slb::integer_sequence; 265 | 266 | #if __GNUC__ >= 8 267 | template 268 | using make_integer_sequence = slb::integer_sequence; 269 | 270 | template 271 | using make_index_sequence = slb::make_integer_sequence; 272 | #elif __has_builtin(__make_integer_seq) || defined(_MSC_VER) 273 | template 274 | using make_integer_sequence = __make_integer_seq; 275 | 276 | template 277 | using make_index_sequence = slb::make_integer_sequence; 278 | #else 279 | namespace detail { 280 | 281 | template 282 | struct expand_index_sequence; 283 | 284 | template 285 | struct expand_index_sequence, true> { 286 | using type = slb::index_sequence; 287 | }; 288 | 289 | template 290 | struct expand_index_sequence, false> { 291 | using type = 292 | slb::index_sequence; 293 | }; 294 | 295 | template 296 | struct make_index_sequence_impl 297 | : expand_index_sequence::type, 298 | N % 2 == 0> { 299 | static_assert(N >= 0, "`N` cannot be negative."); 300 | }; 301 | 302 | template <> 303 | struct make_index_sequence_impl<0> { 304 | using type = slb::index_sequence<>; 305 | }; 306 | 307 | template <> 308 | struct make_index_sequence_impl<1> { 309 | using type = slb::index_sequence<0>; 310 | }; 311 | 312 | template 313 | struct make_integer_sequence_impl; 314 | 315 | template 316 | struct make_integer_sequence_impl> { 317 | using type = slb::integer_sequence(Is)...>; 318 | }; 319 | 320 | } // namespace detail 321 | 322 | template 323 | using make_index_sequence = typename detail::make_index_sequence_impl::type; 324 | 325 | template 326 | using make_integer_sequence = typename detail::make_integer_sequence_impl< 327 | T, 328 | slb::make_index_sequence(N)>>::type; 329 | #endif 330 | 331 | template 332 | using index_sequence_for = slb::make_index_sequence; 333 | 334 | } // namespace slb 335 | 336 | #endif // SLB_UTILITY_HPP 337 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SLB 2 | # 3 | # Copyright Michael Park, 2017 4 | # Copyright Agustin Berge, 2017 5 | # 6 | # Distributed under the Boost Software License, Version 1.0. 7 | # (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 8 | 9 | add_library(Catch2 OBJECT catch.cpp) 10 | 11 | set(_tests 12 | functional/bind 13 | functional/invoke 14 | functional/mem_fn 15 | functional/not_fn 16 | type_traits 17 | utility) 18 | foreach(_test ${_tests}) 19 | set(_test_file ${_test}.cpp) 20 | get_filename_component(_test_folder ${_test_file} DIRECTORY) 21 | string(REPLACE "/" "." _test ${_test}) 22 | 23 | add_executable(test.${_test} ${_test_file} $) 24 | target_link_libraries(test.${_test} SLB) 25 | set_property(TARGET test.${_test} PROPERTY FOLDER "test/${_test_folder}") 26 | 27 | file(STRINGS ${_test_file} _lines) 28 | foreach(_line ${_lines}) 29 | if(_line MATCHES "^TEST_CASE\\(\"([A-Za-z_0-9()-]+)\"") 30 | set(_case ${CMAKE_MATCH_1}) 31 | string(MAKE_C_IDENTIFIER ${_case} _case_id) 32 | 33 | add_test( 34 | NAME test.${_test}.${_case_id} 35 | COMMAND test.${_test} "${_case}") 36 | endif() 37 | endforeach() 38 | endforeach() 39 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # SLB 2 | 3 | > C++ Standard Library Backport 4 | 5 | [![travis][badge.travis]][travis] 6 | [![appveyor][badge.appveyor]][appveyor] 7 | [![license][badge.license]][license] 8 | 9 | [badge.travis]: https://travis-ci.org/mpark/slb.svg?branch=master 10 | [badge.appveyor]: https://ci.appveyor.com/api/projects/status/github/mpark/slb?branch=master&svg=true 11 | [badge.license]: https://img.shields.io/badge/license-boost-blue.svg 12 | 13 | [travis]: https://travis-ci.org/mpark/slb 14 | [appveyor]: https://ci.appveyor.com/project/mpark/slb 15 | [license]: https://github.com/mpark/slb/blob/master/LICENSE.md 16 | 17 | ## Test 18 | 19 | This directory contains the tests for __SLB__. 20 | 21 | ## Build / Run 22 | 23 | Execute the following commands from the top-level directory: 24 | 25 | ```bash 26 | mkdir build && cd build 27 | cmake .. 28 | cmake --build . 29 | ctest --output-on-failure 30 | ``` 31 | -------------------------------------------------------------------------------- /test/catch.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SLB.TypeTraits 3 | 4 | Copyright Michael Park, 2017 5 | Copyright Agustin Berge, 2017 6 | 7 | Distributed under the Boost Software License, Version 1.0. 8 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 9 | */ 10 | 11 | #define CATCH_CONFIG_MAIN 12 | #include "catch.hpp" 13 | -------------------------------------------------------------------------------- /test/functional/bind.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SLB.Functional 3 | 4 | Copyright Michael Park, 2017 5 | Copyright Agustin Berge, 2017 6 | 7 | Distributed under the Boost Software License, Version 1.0. 8 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 9 | */ 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "../catch.hpp" 18 | 19 | #define CHECK_NESTED(...) \ 20 | do { \ 21 | INFO(__FILE__ "(" << __LINE__ << "): " #__VA_ARGS__); \ 22 | check_##__VA_ARGS__; \ 23 | } while (false) 24 | 25 | // [func.bind], bind 26 | 27 | // template struct is_bind_expression; 28 | TEST_CASE("is_bind_expression", "[func.bind.isbind]") { 29 | struct S { 30 | static int f(int base) { return base; } 31 | }; 32 | 33 | // The implementation shall provide a definition that has a base 34 | // characteristic of `true_type` if `T` is a type returned from `bind`, 35 | // otherwise it shall have a base characteristic of `false_type`. 36 | using slb_bind_t = decltype(slb::bind(&S::f, 42)); 37 | CHECK(slb::is_base_of>::value); 39 | CHECK(std::is_bind_expression::value); 40 | 41 | using std_bind_t = decltype(std::bind(&S::f, 42)); 42 | CHECK(std::is_base_of>::value); 44 | 45 | using slb_bind_r_t = decltype(slb::bind(&S::f, 42)); 46 | CHECK(slb::is_base_of>::value); 48 | CHECK(std::is_bind_expression::value); 49 | 50 | using std_bind_r_t = decltype(std::bind(&S::f, 42)); 51 | CHECK(std::is_base_of>::value); 53 | 54 | CHECK(std::is_base_of>::value); 55 | } 56 | 57 | // template struct is_placeholder; 58 | TEST_CASE("is_placeholder", "[func.bind.isplace]") { 59 | 60 | // The implementation shall provide a definition that has the base 61 | // characteristic of `integral_constant` if `T` is the type of 62 | // `std::placeholders::_J`, otherwise it shall have a base characteristic of 63 | // `integral_constant`. 64 | using slb_ph1_t = decltype(slb::placeholders::_1); 65 | CHECK(std::is_base_of, 66 | slb::is_placeholder>::value); 67 | CHECK(slb::is_placeholder::value); 68 | 69 | using std_ph1_t = decltype(std::placeholders::_1); 70 | CHECK(std::is_base_of, 71 | slb::is_placeholder>::value); 72 | 73 | using slb_ph2_t = decltype(slb::placeholders::_2); 74 | CHECK(std::is_base_of, 75 | slb::is_placeholder>::value); 76 | CHECK(slb::is_placeholder::value); 77 | 78 | using std_ph2_t = decltype(std::placeholders::_2); 79 | CHECK(std::is_base_of, 80 | slb::is_placeholder>::value); 81 | 82 | CHECK(std::is_base_of, 83 | slb::is_placeholder>::value); 84 | } 85 | 86 | // template 87 | // unspecified bind(F&&, BoundArgs&&...); 88 | // template 89 | // unspecified bind(F&&, BoundArgs&&...); 90 | struct C { 91 | int obj; 92 | C(int val) : obj(val) {} 93 | 94 | int fun(int base) noexcept { return base + 0; } 95 | int cfun(int base) const noexcept { return base + 1; } 96 | int lfun(int base) & noexcept { return base + 2; } 97 | int rfun(int base) && noexcept { return base + 3; } 98 | int clfun(int base) const& noexcept { return base + 4; } 99 | int crfun(int base) const&& noexcept { return base + 5; } 100 | }; 101 | 102 | struct D : C { 103 | D(int val) : C(val) {} 104 | }; 105 | 106 | template 107 | struct smart_ptr { 108 | T* ptr; 109 | smart_ptr(T* ptr) : ptr(ptr) {} 110 | T& operator*() const noexcept { return *ptr; } 111 | }; 112 | 113 | std::true_type const byval{}; 114 | std::false_type const byref{}; 115 | 116 | template 117 | T const* addressof(T const& ref) { 118 | return &ref; 119 | } 120 | 121 | template 126 | void check_bound_obj( 127 | R&& r, Bound bound, BoundR bound_r, BoundVoid bound_void, Args&&... args) { 128 | CHECK(std::is_base_of>::value); 130 | CHECK(std::is_same(args)...)), R&&>::value); 131 | CHECK(::addressof(bound(std::forward(args)...)) == ::addressof(r)); 132 | 133 | CHECK(std::is_base_of>::value); 135 | CHECK( 136 | std::is_same(args)...)), R&&>::value); 137 | CHECK(::addressof(bound_r(std::forward(args)...)) == ::addressof(r)); 138 | 139 | CHECK(std::is_base_of>::value); 141 | CHECK(std::is_same(args)...)), 142 | void>::value); 143 | bound_void(std::forward(args)...); 144 | } 145 | 146 | template 147 | void check_captured_bound_obj(R&& r, 148 | std::integral_constant, 149 | Bound bound) { 150 | using RD = 151 | typename std::remove_cv::type>::type; 152 | 153 | CHECK(std::is_base_of>::value); 155 | if (ByVal) { 156 | CHECK(std::is_same::value); 157 | CHECK(::addressof(bound()) != ::addressof(r)); 158 | CHECK(bound() == r); 159 | } else { 160 | CHECK(std::is_same::value); 161 | CHECK(::addressof(bound()) == ::addressof(r)); 162 | } 163 | 164 | Bound const bound_const(bound); 165 | CHECK(std::is_base_of>::value); 167 | if (ByVal) { 168 | CHECK(std::is_same::value); 169 | CHECK(::addressof(bound_const()) != ::addressof(r)); 170 | CHECK(bound_const() == r); 171 | } else { 172 | CHECK(std::is_same::value); 173 | CHECK(::addressof(bound_const()) == ::addressof(r)); 174 | } 175 | } 176 | 177 | template 178 | void check_bind_obj(R&& r, 179 | std::integral_constant, 180 | F&& f, 181 | Arg1&& arg1) { 182 | namespace ph = slb::placeholders; 183 | check_bound_obj(std::forward(r), 184 | slb::bind(std::forward(f), ph::_1), 185 | slb::bind(std::forward(f), ph::_1), 186 | slb::bind(std::forward(f), ph::_1), 187 | std::forward(arg1)); 188 | check_captured_bound_obj( 189 | std::forward(r), 190 | std::integral_constant{}, 191 | slb::bind(std::forward(f), std::forward(arg1))); 192 | } 193 | 194 | template 199 | void check_bound_fun( 200 | R&& r, Bound bound, BoundR bound_r, BoundVoid bound_void, Args&&... args) { 201 | CHECK(std::is_base_of>::value); 203 | CHECK(std::is_same(args)...)), R>::value); 204 | CHECK(bound(std::forward(args)...) == r); 205 | 206 | CHECK(std::is_base_of>::value); 208 | CHECK(std::is_same(args)...)), R>::value); 209 | CHECK(bound_r(std::forward(args)...) == r); 210 | 211 | CHECK(std::is_base_of>::value); 213 | CHECK(std::is_same(args)...)), 214 | void>::value); 215 | bound_void(std::forward(args)...); 216 | } 217 | 218 | template 223 | void check_bound_fun_const(R&& r, 224 | Bound const bound, 225 | BoundR const bound_r, 226 | BoundVoid const bound_void, 227 | Args&&... args) { 228 | CHECK(std::is_base_of>::value); 230 | CHECK(std::is_same(args)...)), R>::value); 231 | CHECK(bound(std::forward(args)...) == r); 232 | 233 | CHECK(std::is_base_of>::value); 235 | CHECK(std::is_same(args)...)), R>::value); 236 | CHECK(bound_r(std::forward(args)...) == r); 237 | 238 | CHECK(std::is_base_of>::value); 240 | CHECK(std::is_same(args)...)), 241 | void>::value); 242 | bound_void(std::forward(args)...); 243 | } 244 | 245 | template 246 | void check_bind_fun(R&& r, F&& f, Arg1&& arg1) { 247 | namespace ph = slb::placeholders; 248 | check_bound_fun(std::forward(r), 249 | slb::bind(std::forward(f), ph::_1), 250 | slb::bind(std::forward(f), ph::_1), 251 | slb::bind(std::forward(f), ph::_1), 252 | std::forward(arg1)); 253 | } 254 | 255 | template 256 | void check_bind_fun_const(R&& r, F&& f, Arg1&& arg1) { 257 | namespace ph = slb::placeholders; 258 | check_bound_fun_const(std::forward(r), 259 | slb::bind(std::forward(f), ph::_1), 260 | slb::bind(std::forward(f), ph::_1), 261 | slb::bind(std::forward(f), ph::_1), 262 | std::forward(arg1)); 263 | } 264 | 265 | template 266 | void check_bind_fun(R&& r, F&& f, Arg1&& arg1, Arg2&& arg2) { 267 | namespace ph = slb::placeholders; 268 | check_bound_fun(std::forward(r), 269 | slb::bind(std::forward(f), ph::_1, ph::_2), 270 | slb::bind(std::forward(f), ph::_1, ph::_2), 271 | slb::bind(std::forward(f), ph::_1, ph::_2), 272 | std::forward(arg1), 273 | std::forward(arg2)); 274 | } 275 | 276 | TEST_CASE("bind(mem-obj-ptr)", "[func.bind.bind]") { 277 | auto f = &C::obj; 278 | 279 | /* forwarding call wrapper */ { 280 | using call_wrapper = decltype(slb::bind(f, C{42})); 281 | 282 | CHECK(std::is_move_constructible::value); 283 | CHECK(std::is_copy_constructible::value); 284 | } 285 | 286 | /* reference */ { 287 | C x = {42}; 288 | C& r = x; 289 | C const& cr = x; 290 | 291 | CHECK_NESTED(bind_obj(r.obj, byval, f, r)); 292 | CHECK_NESTED(bind_obj(cr.obj, byval, f, cr)); 293 | CHECK_NESTED(bind_obj(std::move(r.obj), byval, f, std::move(r))); 294 | CHECK_NESTED(bind_obj(std::move(cr.obj), byval, f, std::move(cr))); 295 | 296 | D d = {42}; 297 | D& rd = d; 298 | D const& crd = d; 299 | 300 | CHECK_NESTED(bind_obj(rd.obj, byval, f, rd)); 301 | CHECK_NESTED(bind_obj(crd.obj, byval, f, crd)); 302 | CHECK_NESTED(bind_obj(std::move(rd.obj), byval, f, std::move(rd))); 303 | CHECK_NESTED(bind_obj(std::move(crd.obj), byval, f, std::move(crd))); 304 | } 305 | 306 | /* reference wrapper */ { 307 | C x = {42}; 308 | std::reference_wrapper r = x; 309 | std::reference_wrapper cr = x; 310 | 311 | CHECK_NESTED(bind_obj(r.get().obj, byref, f, r)); 312 | CHECK_NESTED(bind_obj(cr.get().obj, byref, f, cr)); 313 | } 314 | 315 | /* pointer */ { 316 | C x = {42}; 317 | C* p = &x; 318 | C const* cp = &x; 319 | 320 | CHECK_NESTED(bind_obj((*p).obj, byref, f, p)); 321 | CHECK_NESTED(bind_obj((*cp).obj, byref, f, cp)); 322 | } 323 | 324 | /* smart pointer */ { 325 | C x = {42}; 326 | smart_ptr p = &x; 327 | smart_ptr cp = &x; 328 | 329 | CHECK_NESTED(bind_obj((*p).obj, byref, f, p)); 330 | CHECK_NESTED(bind_obj((*cp).obj, byref, f, cp)); 331 | } 332 | } 333 | 334 | TEST_CASE("bind(mem-fun-ptr)", "[func.bind.bind]") { 335 | auto f = &C::fun; 336 | 337 | /* forwarding call wrapper */ { 338 | using call_wrapper = decltype(slb::bind(f, C{42})); 339 | 340 | CHECK(std::is_move_constructible::value); 341 | CHECK(std::is_copy_constructible::value); 342 | } 343 | 344 | auto cf = &C::cfun; 345 | auto lf = &C::lfun; 346 | auto rf = &C::rfun; 347 | auto clf = &C::clfun; 348 | auto crf = &C::crfun; 349 | 350 | /* reference */ { 351 | C x = {42}; 352 | C& r = x; 353 | C const& cr = x; 354 | 355 | CHECK_NESTED(bind_fun(r.fun(40), f, r, 40)); 356 | CHECK_NESTED(bind_fun(r.cfun(40), cf, r, 40)); 357 | CHECK_NESTED(bind_fun(r.lfun(40), lf, r, 40)); 358 | CHECK_NESTED(bind_fun(r.clfun(40), clf, r, 40)); 359 | 360 | CHECK_NESTED(bind_fun(cr.cfun(40), cf, cr, 40)); 361 | CHECK_NESTED(bind_fun(cr.clfun(40), clf, cr, 40)); 362 | 363 | CHECK_NESTED(bind_fun(std::move(r).fun(40), f, std::move(r), 40)); 364 | CHECK_NESTED(bind_fun(std::move(r).cfun(40), cf, std::move(r), 40)); 365 | CHECK_NESTED(bind_fun(std::move(r).clfun(40), clf, std::move(r), 40)); 366 | CHECK_NESTED(bind_fun(std::move(r).rfun(40), rf, std::move(r), 40)); 367 | CHECK_NESTED(bind_fun(std::move(r).crfun(40), crf, std::move(r), 40)); 368 | 369 | CHECK_NESTED(bind_fun(std::move(cr).cfun(40), cf, std::move(cr), 40)); 370 | CHECK_NESTED(bind_fun(std::move(cr).clfun(40), clf, std::move(cr), 40)); 371 | CHECK_NESTED(bind_fun(std::move(cr).crfun(40), crf, std::move(cr), 40)); 372 | } 373 | 374 | /* reference wrapper */ { 375 | C x = {42}; 376 | std::reference_wrapper r = x; 377 | std::reference_wrapper cr = x; 378 | 379 | CHECK_NESTED(bind_fun(r.get().fun(40), f, r, 40)); 380 | CHECK_NESTED(bind_fun(r.get().cfun(40), cf, r, 40)); 381 | CHECK_NESTED(bind_fun(r.get().lfun(40), lf, r, 40)); 382 | CHECK_NESTED(bind_fun(r.get().clfun(40), clf, r, 40)); 383 | 384 | CHECK_NESTED(bind_fun(cr.get().cfun(40), cf, cr, 40)); 385 | CHECK_NESTED(bind_fun(cr.get().clfun(40), clf, cr, 40)); 386 | } 387 | 388 | /* pointer */ { 389 | C x = {42}; 390 | C* p = &x; 391 | C const* cp = &x; 392 | 393 | CHECK_NESTED(bind_fun((*p).fun(40), f, p, 40)); 394 | CHECK_NESTED(bind_fun((*p).cfun(40), cf, p, 40)); 395 | CHECK_NESTED(bind_fun((*p).lfun(40), lf, p, 40)); 396 | CHECK_NESTED(bind_fun((*p).clfun(40), clf, p, 40)); 397 | 398 | CHECK_NESTED(bind_fun((*cp).cfun(40), cf, cp, 40)); 399 | CHECK_NESTED(bind_fun((*cp).clfun(40), clf, cp, 40)); 400 | } 401 | 402 | /* smart pointer */ { 403 | C x = {42}; 404 | smart_ptr p = &x; 405 | smart_ptr cp = &x; 406 | 407 | CHECK_NESTED(bind_fun((*p).fun(40), f, p, 40)); 408 | CHECK_NESTED(bind_fun((*p).cfun(40), cf, p, 40)); 409 | CHECK_NESTED(bind_fun((*p).lfun(40), lf, p, 40)); 410 | CHECK_NESTED(bind_fun((*p).clfun(40), clf, p, 40)); 411 | 412 | CHECK_NESTED(bind_fun((*cp).cfun(40), cf, cp, 40)); 413 | CHECK_NESTED(bind_fun((*cp).clfun(40), clf, cp, 40)); 414 | } 415 | } 416 | 417 | TEST_CASE("bind(fun-obj)", "[func.bind.bind]") { 418 | /* forwarding call wrapper */ { 419 | struct Fn { 420 | Fn() {} 421 | Fn(Fn&&) = default; 422 | Fn(Fn const&) = delete; 423 | void operator()(){}; 424 | }; 425 | using call_wrapper = decltype(slb::bind(Fn{})); 426 | 427 | CHECK(std::is_move_constructible::value); 428 | CHECK(!std::is_copy_constructible::value); 429 | } 430 | 431 | /* call-op */ { 432 | struct Fn { 433 | int operator()(int base) noexcept { return base + 6; } 434 | int operator()(int base) const noexcept { return base + 7; } 435 | }; 436 | auto f = Fn{}; 437 | auto const& fc = f; 438 | 439 | CHECK_NESTED(bind_fun(f(40), f, 40)); 440 | CHECK_NESTED(bind_fun_const(fc(40), f, 40)); 441 | } 442 | 443 | /* fun-ptr */ { 444 | struct S { 445 | static int f(int base) noexcept { return base + 8; } 446 | }; 447 | auto f = &S::f; 448 | 449 | CHECK_NESTED(bind_fun(f(40), f, 40)); 450 | } 451 | } 452 | 453 | #if SLB_HAS_CXX14_VARIABLE_TEMPLATES 454 | // template 455 | // inline constexpr bool is_bind_expression_v = is_bind_expression::value; 456 | TEST_CASE("is_bind_expression_v", "[functional.syn]") { 457 | struct S { 458 | static int f(int base) { return base; } 459 | }; 460 | 461 | using slb_bind_t = decltype(slb::bind(&S::f, 42)); 462 | CHECK(slb::is_same), 463 | const bool>::value); 464 | CHECK(slb::is_bind_expression_v == 465 | slb::is_bind_expression::value); 466 | constexpr bool slb_bind_v = slb::is_bind_expression_v; 467 | (void)slb_bind_v; 468 | 469 | using std_bind_t = decltype(std::bind(&S::f, 42)); 470 | CHECK(std::is_same), 471 | const bool>::value); 472 | CHECK(slb::is_bind_expression_v == 473 | slb::is_bind_expression::value); 474 | constexpr bool std_bind_v = slb::is_bind_expression_v; 475 | (void)std_bind_v; 476 | 477 | using slb_bind_r_t = decltype(slb::bind(&S::f, 42)); 478 | CHECK(slb::is_same), 479 | const bool>::value); 480 | CHECK(slb::is_bind_expression_v == 481 | slb::is_bind_expression::value); 482 | constexpr bool slb_bind_r_v = slb::is_bind_expression_v; 483 | (void)slb_bind_r_v; 484 | 485 | using std_bind_r_t = decltype(std::bind(&S::f, 42)); 486 | CHECK(std::is_same), 487 | const bool>::value); 488 | CHECK(slb::is_bind_expression_v == 489 | slb::is_bind_expression::value); 490 | constexpr bool std_bind_r_v = slb::is_bind_expression_v; 491 | (void)std_bind_r_v; 492 | 493 | CHECK(slb::is_bind_expression_v == slb::is_bind_expression::value); 494 | CHECK(std::is_same), 495 | const bool>::value); 496 | CHECK(slb::is_bind_expression_v == slb::is_bind_expression::value); 497 | constexpr bool int_v = slb::is_bind_expression_v; 498 | (void)int_v; 499 | } 500 | 501 | // template 502 | // inline constexpr int is_placeholder_v = is_placeholder::value; 503 | TEST_CASE("is_placeholder_v", "[functional.syn]") { 504 | using slb_ph1_t = decltype(slb::placeholders::_1); 505 | CHECK(std::is_same), 506 | const int>::value); 507 | CHECK(slb::is_placeholder_v == 508 | slb::is_placeholder::value); 509 | constexpr int slb_ph1_v = slb::is_placeholder_v; 510 | (void)slb_ph1_v; 511 | 512 | using std_ph1_t = decltype(std::placeholders::_1); 513 | CHECK(std::is_same), 514 | const int>::value); 515 | CHECK(slb::is_placeholder_v == 516 | slb::is_placeholder::value); 517 | constexpr int std_ph1_v = slb::is_placeholder_v; 518 | (void)std_ph1_v; 519 | 520 | using slb_ph2_t = decltype(slb::placeholders::_2); 521 | CHECK(std::is_same), 522 | const int>::value); 523 | CHECK(slb::is_placeholder_v == 524 | slb::is_placeholder::value); 525 | constexpr int slb_ph2_v = slb::is_placeholder_v; 526 | (void)slb_ph2_v; 527 | 528 | using std_ph2_t = decltype(std::placeholders::_2); 529 | CHECK(std::is_same), 530 | const int>::value); 531 | CHECK(slb::is_placeholder_v == 532 | slb::is_placeholder::value); 533 | constexpr int std_ph2_v = slb::is_placeholder_v; 534 | (void)std_ph2_v; 535 | 536 | CHECK(std::is_same), const int>::value); 537 | CHECK(slb::is_placeholder_v == slb::is_placeholder::value); 538 | constexpr int int_v = slb::is_placeholder_v; 539 | (void)int_v; 540 | } 541 | #endif 542 | -------------------------------------------------------------------------------- /test/functional/invoke.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SLB.Functional 3 | 4 | Copyright Michael Park, 2017 5 | Copyright Agustin Berge, 2017 6 | 7 | Distributed under the Boost Software License, Version 1.0. 8 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 9 | */ 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #include "../catch.hpp" 17 | 18 | #define CHECK_NESTED(...) \ 19 | do { \ 20 | INFO(__FILE__ "(" << __LINE__ << "): " #__VA_ARGS__); \ 21 | check_##__VA_ARGS__; \ 22 | } while (false) 23 | 24 | // [func.invoke], invoke 25 | 26 | // template 27 | // invoke_result_t invoke(F&& f, Args&&... args) 28 | // noexcept(is_nothrow_invocable_v); 29 | 30 | // Account for P0012: "Make exception specifications be part of the type 31 | // system". 32 | static constexpr bool p0012 = !std::is_same::value; 33 | 34 | struct C { 35 | int obj; 36 | C(int val) : obj(val) {} 37 | 38 | int fun(int base) noexcept(p0012) { return base + 0; } 39 | int cfun(int base) const noexcept(p0012) { return base + 1; } 40 | int lfun(int base) & noexcept(p0012) { return base + 2; } 41 | int rfun(int base) && noexcept(p0012) { return base + 3; } 42 | int clfun(int base) const& noexcept(p0012) { return base + 4; } 43 | int crfun(int base) const&& noexcept(p0012) { return base + 5; } 44 | }; 45 | 46 | struct D : C { 47 | D(int val) : C(val) {} 48 | }; 49 | 50 | template 51 | struct smart_ptr { 52 | T* ptr; 53 | smart_ptr(T* ptr) : ptr(ptr) {} 54 | T& operator*() const noexcept(IsNothrow) { return *ptr; } 55 | }; 56 | template 57 | using smart_ptr_throws = smart_ptr; 58 | 59 | template 60 | struct conv_to { 61 | T val; 62 | conv_to(T val) : val(val) {} 63 | operator T() const noexcept(IsNothrow) { return val; } 64 | }; 65 | template 66 | using conv_to_throws = conv_to; 67 | 68 | std::true_type const nothrows{}; 69 | std::false_type const throws{}; 70 | std::integral_constant const p0012_nothrows{}; 71 | 72 | template 73 | T const* addressof(T const& ref) { 74 | return &ref; 75 | } 76 | 77 | template 78 | void check_invoke_obj(R&& r, 79 | std::integral_constant, 80 | F&& f, 81 | A1&& a1) { 82 | CHECK(::addressof(slb::invoke(std::forward(f), std::forward(a1))) == 83 | ::addressof(r)); 84 | CHECK(std::is_same(f), std::forward(a1))), 86 | R&&>::value); 87 | CHECK(noexcept(slb::invoke(std::forward(f), std::forward(a1))) == 88 | IsNothrow); 89 | } 90 | 91 | template 92 | void check_invoke_fun(R&& r, 93 | std::integral_constant, 94 | F&& f, 95 | Args&&... args) { 96 | CHECK(slb::invoke(std::forward(f), std::forward(args)...) == r); 97 | CHECK(std::is_same(f), 98 | std::forward(args)...)), 99 | R>::value); 100 | CHECK(noexcept(slb::invoke(std::forward(f), 101 | std::forward(args)...)) == IsNothrow); 102 | } 103 | 104 | TEST_CASE("invoke(mem-obj-ptr)", "[func.invoke]") { 105 | auto f = &C::obj; 106 | 107 | /* reference */ { 108 | C x = {42}; 109 | C& r = x; 110 | C const& cr = x; 111 | 112 | CHECK_NESTED(invoke_obj(r.obj, nothrows, f, r)); 113 | CHECK_NESTED(invoke_obj(cr.obj, nothrows, f, cr)); 114 | CHECK_NESTED(invoke_obj(std::move(r.obj), nothrows, f, std::move(r))); 115 | CHECK_NESTED(invoke_obj(std::move(cr.obj), nothrows, f, std::move(cr))); 116 | 117 | D d = {42}; 118 | D& rd = d; 119 | D const& crd = d; 120 | 121 | CHECK_NESTED(invoke_obj(rd.obj, nothrows, f, rd)); 122 | CHECK_NESTED(invoke_obj(crd.obj, nothrows, f, crd)); 123 | CHECK_NESTED(invoke_obj(std::move(rd.obj), nothrows, f, std::move(rd))); 124 | CHECK_NESTED(invoke_obj(std::move(crd.obj), nothrows, f, std::move(crd))); 125 | } 126 | 127 | /* reference wrapper */ { 128 | C x = {42}; 129 | std::reference_wrapper r = x; 130 | std::reference_wrapper cr = x; 131 | 132 | CHECK_NESTED(invoke_obj(r.get().obj, nothrows, f, r)); 133 | CHECK_NESTED(invoke_obj(cr.get().obj, nothrows, f, cr)); 134 | } 135 | 136 | /* pointer */ { 137 | C x = {42}; 138 | C* p = &x; 139 | C const* cp = &x; 140 | 141 | CHECK_NESTED(invoke_obj((*p).obj, nothrows, f, p)); 142 | CHECK_NESTED(invoke_obj((*cp).obj, nothrows, f, cp)); 143 | } 144 | 145 | /* smart pointer */ { 146 | C x = {42}; 147 | smart_ptr p = &x; 148 | smart_ptr cp = &x; 149 | 150 | CHECK_NESTED(invoke_obj((*p).obj, nothrows, f, p)); 151 | CHECK_NESTED(invoke_obj((*cp).obj, nothrows, f, cp)); 152 | 153 | smart_ptr_throws tp = &x; 154 | smart_ptr_throws tcp = &x; 155 | 156 | CHECK_NESTED(invoke_obj((*tp).obj, throws, f, tp)); 157 | CHECK_NESTED(invoke_obj((*tcp).obj, throws, f, tcp)); 158 | } 159 | } 160 | 161 | TEST_CASE("invoke(mem-fun-ptr)", "[func.invoke]") { 162 | auto f = &C::fun; 163 | auto cf = &C::cfun; 164 | auto lf = &C::lfun; 165 | auto rf = &C::rfun; 166 | auto clf = &C::clfun; 167 | auto crf = &C::crfun; 168 | 169 | /* reference */ { 170 | C x = {42}; 171 | C& r = x; 172 | C const& cr = x; 173 | 174 | CHECK_NESTED(invoke_fun(r.fun(40), p0012_nothrows, f, r, 40)); 175 | CHECK_NESTED(invoke_fun(r.cfun(40), p0012_nothrows, cf, r, 40)); 176 | CHECK_NESTED(invoke_fun(r.lfun(40), p0012_nothrows, lf, r, 40)); 177 | CHECK_NESTED(invoke_fun(r.clfun(40), p0012_nothrows, clf, r, 40)); 178 | 179 | CHECK_NESTED(invoke_fun(cr.cfun(40), p0012_nothrows, cf, cr, 40)); 180 | CHECK_NESTED(invoke_fun(cr.clfun(40), p0012_nothrows, clf, cr, 40)); 181 | 182 | CHECK_NESTED( 183 | invoke_fun(std::move(r).fun(40), p0012_nothrows, f, std::move(r), 40)); 184 | CHECK_NESTED(invoke_fun( 185 | std::move(r).cfun(40), p0012_nothrows, cf, std::move(r), 40)); 186 | CHECK_NESTED(invoke_fun( 187 | std::move(r).clfun(40), p0012_nothrows, clf, std::move(r), 40)); 188 | CHECK_NESTED(invoke_fun( 189 | std::move(r).rfun(40), p0012_nothrows, rf, std::move(r), 40)); 190 | CHECK_NESTED(invoke_fun( 191 | std::move(r).crfun(40), p0012_nothrows, crf, std::move(r), 40)); 192 | 193 | CHECK_NESTED(invoke_fun( 194 | std::move(cr).cfun(40), p0012_nothrows, cf, std::move(cr), 40)); 195 | CHECK_NESTED(invoke_fun( 196 | std::move(cr).clfun(40), p0012_nothrows, clf, std::move(cr), 40)); 197 | CHECK_NESTED(invoke_fun( 198 | std::move(cr).crfun(40), p0012_nothrows, crf, std::move(cr), 40)); 199 | } 200 | 201 | /* reference wrapper */ { 202 | C x = {42}; 203 | std::reference_wrapper r = x; 204 | std::reference_wrapper cr = x; 205 | 206 | CHECK_NESTED(invoke_fun(r.get().fun(40), p0012_nothrows, f, r, 40)); 207 | CHECK_NESTED(invoke_fun(r.get().cfun(40), p0012_nothrows, cf, r, 40)); 208 | CHECK_NESTED(invoke_fun(r.get().lfun(40), p0012_nothrows, lf, r, 40)); 209 | CHECK_NESTED(invoke_fun(r.get().clfun(40), p0012_nothrows, clf, r, 40)); 210 | 211 | CHECK_NESTED(invoke_fun(cr.get().cfun(40), p0012_nothrows, cf, cr, 40)); 212 | CHECK_NESTED(invoke_fun(cr.get().clfun(40), p0012_nothrows, clf, cr, 40)); 213 | } 214 | 215 | /* pointer */ { 216 | C x = {42}; 217 | C* p = &x; 218 | C const* cp = &x; 219 | 220 | CHECK_NESTED(invoke_fun((*p).fun(40), p0012_nothrows, f, p, 40)); 221 | CHECK_NESTED(invoke_fun((*p).cfun(40), p0012_nothrows, cf, p, 40)); 222 | CHECK_NESTED(invoke_fun((*p).lfun(40), p0012_nothrows, lf, p, 40)); 223 | CHECK_NESTED(invoke_fun((*p).clfun(40), p0012_nothrows, clf, p, 40)); 224 | 225 | CHECK_NESTED(invoke_fun((*cp).cfun(40), p0012_nothrows, cf, cp, 40)); 226 | CHECK_NESTED(invoke_fun((*cp).clfun(40), p0012_nothrows, clf, cp, 40)); 227 | } 228 | 229 | /* smart pointer */ { 230 | C x = {42}; 231 | smart_ptr p = &x; 232 | smart_ptr cp = &x; 233 | 234 | CHECK_NESTED(invoke_fun((*p).fun(40), p0012_nothrows, f, p, 40)); 235 | CHECK_NESTED(invoke_fun((*p).cfun(40), p0012_nothrows, cf, p, 40)); 236 | CHECK_NESTED(invoke_fun((*p).lfun(40), p0012_nothrows, lf, p, 40)); 237 | CHECK_NESTED(invoke_fun((*p).clfun(40), p0012_nothrows, clf, p, 40)); 238 | 239 | CHECK_NESTED(invoke_fun((*cp).cfun(40), p0012_nothrows, cf, cp, 40)); 240 | CHECK_NESTED(invoke_fun((*cp).clfun(40), p0012_nothrows, clf, cp, 40)); 241 | 242 | smart_ptr_throws tp = &x; 243 | smart_ptr_throws tcp = &x; 244 | 245 | CHECK_NESTED(invoke_fun((*tp).fun(40), throws, f, tp, 40)); 246 | CHECK_NESTED(invoke_fun((*tp).cfun(40), throws, cf, tp, 40)); 247 | CHECK_NESTED(invoke_fun((*tp).lfun(40), throws, lf, tp, 40)); 248 | CHECK_NESTED(invoke_fun((*tp).clfun(40), throws, clf, tp, 40)); 249 | 250 | CHECK_NESTED(invoke_fun((*tcp).cfun(40), throws, cf, tcp, 40)); 251 | CHECK_NESTED(invoke_fun((*tcp).clfun(40), throws, clf, tcp, 40)); 252 | } 253 | } 254 | 255 | TEST_CASE("invoke(fun-obj)", "[func.invoke]") { 256 | /* call-op */ { 257 | struct Fn { 258 | int operator()(int base) noexcept { return base + 6; } 259 | }; 260 | auto f = Fn{}; 261 | 262 | CHECK_NESTED(invoke_fun(f(40), nothrows, f, 40)); 263 | CHECK_NESTED( 264 | invoke_fun(f(conv_to(40)), nothrows, f, conv_to(40))); 265 | CHECK_NESTED(invoke_fun( 266 | f(conv_to_throws(40)), throws, f, conv_to_throws(40))); 267 | } 268 | 269 | /* fun-ptr */ { 270 | struct S { 271 | static int f(int base) noexcept(p0012) { return base + 7; } 272 | }; 273 | auto f = &S::f; 274 | 275 | CHECK_NESTED(invoke_fun(f(40), p0012_nothrows, f, 40)); 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /test/functional/mem_fn.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SLB.Functional 3 | 4 | Copyright Michael Park, 2017 5 | Copyright Agustin Berge, 2017 6 | 7 | Distributed under the Boost Software License, Version 1.0. 8 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 9 | */ 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #include "../catch.hpp" 17 | 18 | #define CHECK_NESTED(...) \ 19 | do { \ 20 | INFO(__FILE__ "(" << __LINE__ << "): " #__VA_ARGS__); \ 21 | check_##__VA_ARGS__; \ 22 | } while (false) 23 | 24 | // [func.memfn], member function adaptors 25 | 26 | // template 27 | // unspecified mem_fn(R T::*) noexcept; 28 | 29 | // Account for P0012: "Make exception specifications be part of the type 30 | // system". 31 | static constexpr bool p0012 = !std::is_same::value; 32 | 33 | struct C { 34 | int obj; 35 | C(int val) : obj(val) {} 36 | 37 | int fun(int base) noexcept(p0012) { return base + 0; } 38 | int cfun(int base) const noexcept(p0012) { return base + 1; } 39 | int lfun(int base) & noexcept(p0012) { return base + 2; } 40 | int rfun(int base) && noexcept(p0012) { return base + 3; } 41 | int clfun(int base) const& noexcept(p0012) { return base + 4; } 42 | int crfun(int base) const&& noexcept(p0012) { return base + 5; } 43 | }; 44 | 45 | struct D : C { 46 | D(int val) : C(val) {} 47 | }; 48 | 49 | template 50 | struct smart_ptr { 51 | T* ptr; 52 | smart_ptr(T* ptr) : ptr(ptr) {} 53 | T& operator*() const noexcept(IsNothrow) { return *ptr; } 54 | }; 55 | template 56 | using smart_ptr_throws = smart_ptr; 57 | 58 | std::true_type const nothrows{}; 59 | std::false_type const throws{}; 60 | std::integral_constant const p0012_nothrows{}; 61 | 62 | template 63 | T const* addressof(T const& ref) { 64 | return &ref; 65 | } 66 | 67 | template 68 | void check_mem_obj(R&& r, 69 | std::integral_constant, 70 | F mem, 71 | T1&& t1) { 72 | CHECK(::addressof(mem(std::forward(t1))) == ::addressof(r)); 73 | CHECK(std::is_same(t1))), R&&>::value); 74 | CHECK(noexcept(mem(std::forward(t1))) == IsNothrow); 75 | } 76 | 77 | template 78 | void check_mem_fun(R const& r, 79 | std::integral_constant, 80 | F mem, 81 | Tn&&... tn) { 82 | CHECK(mem(std::forward(tn)...) == r); 83 | CHECK(std::is_same(tn)...)), R>::value); 84 | CHECK(noexcept(mem(std::forward(tn)...)) == IsNothrow); 85 | } 86 | 87 | TEST_CASE("mem_fn(mem-obj-ptr)", "[func.memfn]") { 88 | auto mem = slb::mem_fn(&C::obj); 89 | CHECK(noexcept(slb::mem_fn(&C::obj))); 90 | 91 | /* simple call wrapper */ { 92 | using call_wrapper = decltype(mem); 93 | 94 | CHECK(std::is_move_constructible::value); 95 | CHECK(std::is_copy_constructible::value); 96 | CHECK(std::is_move_assignable::value); 97 | CHECK(std::is_copy_assignable::value); 98 | 99 | CHECK(std::is_nothrow_move_constructible::value); 100 | CHECK(std::is_nothrow_copy_constructible::value); 101 | CHECK(std::is_nothrow_move_assignable::value); 102 | CHECK(std::is_nothrow_copy_assignable::value); 103 | } 104 | 105 | /* reference */ { 106 | C x = {42}; 107 | C& r = x; 108 | C const& cr = x; 109 | 110 | CHECK_NESTED(mem_obj(r.obj, nothrows, mem, r)); 111 | CHECK_NESTED(mem_obj(cr.obj, nothrows, mem, cr)); 112 | CHECK_NESTED(mem_obj(std::move(r.obj), nothrows, mem, std::move(r))); 113 | CHECK_NESTED(mem_obj(std::move(cr.obj), nothrows, mem, std::move(cr))); 114 | 115 | D d = {42}; 116 | D& rd = d; 117 | D const& crd = d; 118 | 119 | CHECK_NESTED(mem_obj(rd.obj, nothrows, mem, rd)); 120 | CHECK_NESTED(mem_obj(crd.obj, nothrows, mem, crd)); 121 | CHECK_NESTED(mem_obj(std::move(rd.obj), nothrows, mem, std::move(rd))); 122 | CHECK_NESTED(mem_obj(std::move(crd.obj), nothrows, mem, std::move(crd))); 123 | } 124 | 125 | /* reference wrapper */ { 126 | C x = {42}; 127 | std::reference_wrapper r = x; 128 | std::reference_wrapper cr = x; 129 | 130 | CHECK_NESTED(mem_obj(r.get().obj, nothrows, mem, r)); 131 | CHECK_NESTED(mem_obj(cr.get().obj, nothrows, mem, cr)); 132 | } 133 | 134 | /* pointer */ { 135 | C x = {42}; 136 | C* p = &x; 137 | C const* cp = &x; 138 | 139 | CHECK_NESTED(mem_obj((*p).obj, nothrows, mem, p)); 140 | CHECK_NESTED(mem_obj((*cp).obj, nothrows, mem, cp)); 141 | } 142 | 143 | /* smart pointer */ { 144 | C x = {42}; 145 | smart_ptr p = &x; 146 | smart_ptr cp = &x; 147 | 148 | CHECK_NESTED(mem_obj((*p).obj, nothrows, mem, p)); 149 | CHECK_NESTED(mem_obj((*cp).obj, nothrows, mem, cp)); 150 | 151 | smart_ptr_throws tp = &x; 152 | smart_ptr_throws tcp = &x; 153 | 154 | CHECK_NESTED(mem_obj((*tp).obj, throws, mem, tp)); 155 | CHECK_NESTED(mem_obj((*tcp).obj, throws, mem, tcp)); 156 | } 157 | } 158 | 159 | TEST_CASE("mem_fn(mem-fun-ptr)", "[func.memfn]") { 160 | auto mem = slb::mem_fn(&C::fun); 161 | CHECK(noexcept(slb::mem_fn(&C::fun))); 162 | 163 | /* simple call wrapper */ { 164 | using call_wrapper = decltype(mem); 165 | 166 | CHECK(std::is_move_constructible::value); 167 | CHECK(std::is_copy_constructible::value); 168 | CHECK(std::is_move_assignable::value); 169 | CHECK(std::is_copy_assignable::value); 170 | 171 | CHECK(std::is_nothrow_move_constructible::value); 172 | CHECK(std::is_nothrow_copy_constructible::value); 173 | CHECK(std::is_nothrow_move_assignable::value); 174 | CHECK(std::is_nothrow_copy_assignable::value); 175 | } 176 | 177 | auto cmem = slb::mem_fn(&C::cfun); 178 | auto lmem = slb::mem_fn(&C::lfun); 179 | auto rmem = slb::mem_fn(&C::rfun); 180 | auto clmem = slb::mem_fn(&C::clfun); 181 | auto crmem = slb::mem_fn(&C::crfun); 182 | 183 | /* reference */ { 184 | C x = {42}; 185 | C& r = x; 186 | C const& cr = x; 187 | 188 | CHECK_NESTED(mem_fun(r.fun(40), p0012_nothrows, mem, r, 40)); 189 | CHECK_NESTED(mem_fun(r.cfun(40), p0012_nothrows, cmem, r, 40)); 190 | CHECK_NESTED(mem_fun(r.lfun(40), p0012_nothrows, lmem, r, 40)); 191 | CHECK_NESTED(mem_fun(r.clfun(40), p0012_nothrows, clmem, r, 40)); 192 | 193 | CHECK_NESTED(mem_fun(cr.cfun(40), p0012_nothrows, cmem, cr, 40)); 194 | CHECK_NESTED(mem_fun(cr.clfun(40), p0012_nothrows, clmem, cr, 40)); 195 | 196 | CHECK_NESTED( 197 | mem_fun(std::move(r).fun(40), p0012_nothrows, mem, std::move(r), 40)); 198 | CHECK_NESTED( 199 | mem_fun(std::move(r).cfun(40), p0012_nothrows, cmem, std::move(r), 40)); 200 | CHECK_NESTED(mem_fun( 201 | std::move(r).clfun(40), p0012_nothrows, clmem, std::move(r), 40)); 202 | CHECK_NESTED( 203 | mem_fun(std::move(r).rfun(40), p0012_nothrows, rmem, std::move(r), 40)); 204 | CHECK_NESTED(mem_fun( 205 | std::move(r).crfun(40), p0012_nothrows, crmem, std::move(r), 40)); 206 | 207 | CHECK_NESTED(mem_fun( 208 | std::move(cr).cfun(40), p0012_nothrows, cmem, std::move(cr), 40)); 209 | CHECK_NESTED(mem_fun( 210 | std::move(cr).clfun(40), p0012_nothrows, clmem, std::move(cr), 40)); 211 | CHECK_NESTED(mem_fun( 212 | std::move(cr).crfun(40), p0012_nothrows, crmem, std::move(cr), 40)); 213 | } 214 | 215 | /* reference wrapper */ { 216 | C x = {42}; 217 | std::reference_wrapper r = x; 218 | std::reference_wrapper cr = x; 219 | 220 | CHECK_NESTED(mem_fun(r.get().fun(40), p0012_nothrows, mem, r, 40)); 221 | CHECK_NESTED(mem_fun(r.get().cfun(40), p0012_nothrows, cmem, r, 40)); 222 | CHECK_NESTED(mem_fun(r.get().lfun(40), p0012_nothrows, lmem, r, 40)); 223 | CHECK_NESTED(mem_fun(r.get().clfun(40), p0012_nothrows, clmem, r, 40)); 224 | 225 | CHECK_NESTED(mem_fun(cr.get().cfun(40), p0012_nothrows, cmem, cr, 40)); 226 | CHECK_NESTED(mem_fun(cr.get().clfun(40), p0012_nothrows, clmem, cr, 40)); 227 | } 228 | 229 | /* pointer */ { 230 | C x = {42}; 231 | C* p = &x; 232 | C const* cp = &x; 233 | 234 | CHECK_NESTED(mem_fun((*p).fun(40), p0012_nothrows, mem, p, 40)); 235 | CHECK_NESTED(mem_fun((*p).cfun(40), p0012_nothrows, cmem, p, 40)); 236 | CHECK_NESTED(mem_fun((*p).lfun(40), p0012_nothrows, lmem, p, 40)); 237 | CHECK_NESTED(mem_fun((*p).clfun(40), p0012_nothrows, clmem, p, 40)); 238 | 239 | CHECK_NESTED(mem_fun((*cp).cfun(40), p0012_nothrows, cmem, cp, 40)); 240 | CHECK_NESTED(mem_fun((*cp).clfun(40), p0012_nothrows, clmem, cp, 40)); 241 | } 242 | 243 | /* smart pointer */ { 244 | C x = {42}; 245 | smart_ptr p = &x; 246 | smart_ptr cp = &x; 247 | 248 | CHECK_NESTED(mem_fun((*p).fun(40), p0012_nothrows, mem, p, 40)); 249 | CHECK_NESTED(mem_fun((*p).cfun(40), p0012_nothrows, cmem, p, 40)); 250 | CHECK_NESTED(mem_fun((*p).lfun(40), p0012_nothrows, lmem, p, 40)); 251 | CHECK_NESTED(mem_fun((*p).clfun(40), p0012_nothrows, clmem, p, 40)); 252 | 253 | CHECK_NESTED(mem_fun((*cp).cfun(40), p0012_nothrows, cmem, cp, 40)); 254 | CHECK_NESTED(mem_fun((*cp).clfun(40), p0012_nothrows, clmem, cp, 40)); 255 | 256 | smart_ptr_throws tp = &x; 257 | smart_ptr_throws tcp = &x; 258 | 259 | CHECK_NESTED(mem_fun((*tp).fun(40), throws, mem, tp, 40)); 260 | CHECK_NESTED(mem_fun((*tp).cfun(40), throws, cmem, tp, 40)); 261 | CHECK_NESTED(mem_fun((*tp).lfun(40), throws, lmem, tp, 40)); 262 | CHECK_NESTED(mem_fun((*tp).clfun(40), throws, clmem, tp, 40)); 263 | 264 | CHECK_NESTED(mem_fun((*tcp).cfun(40), throws, cmem, tcp, 40)); 265 | CHECK_NESTED(mem_fun((*tcp).clfun(40), throws, clmem, tcp, 40)); 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /test/functional/not_fn.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SLB.Functional 3 | 4 | Copyright Michael Park, 2017 5 | Copyright Agustin Berge, 2017 6 | 7 | Distributed under the Boost Software License, Version 1.0. 8 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 9 | */ 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "../catch.hpp" 18 | 19 | #define CHECK_NESTED(...) \ 20 | do { \ 21 | INFO(__FILE__ "(" << __LINE__ << "): " #__VA_ARGS__); \ 22 | check_##__VA_ARGS__; \ 23 | } while (false) 24 | 25 | // [func.not_fn], function template not_fn 26 | 27 | // template unspecified not_fn(F&& f); 28 | 29 | enum lvalue : int {}; 30 | enum rvalue : int {}; 31 | enum const_lvalue : int {}; 32 | enum const_rvalue : int {}; 33 | 34 | template 35 | struct Boolean { 36 | int ret; 37 | Boolean(int val) : ret(val) {} 38 | 39 | T operator!() const noexcept { return static_cast(ret); } 40 | }; 41 | 42 | struct BooleanObj { 43 | int base; 44 | BooleanObj(int val) : base(val) {} 45 | 46 | int operator!() & noexcept { return base - 1; } 47 | int operator!() && noexcept { return base - 2; } 48 | int operator!() const & noexcept { return base - 3; } 49 | // gcc finds calls on const rvalues ambiguous up to version 4.8. 50 | #if !defined(__GNUC__) || (__GNUC__ > 4) || \ 51 | ((__GNUC__ == 4) && (__GNUC_MINOR__ > 8)) 52 | int operator!() const && noexcept { return base - 4; } 53 | #endif 54 | }; 55 | 56 | // Account for P0012: "Make exception specifications be part of the type 57 | // system". 58 | static constexpr bool p0012 = !std::is_same::value; 59 | 60 | struct C { 61 | BooleanObj obj; 62 | C(int val) : obj(val) {} 63 | 64 | Boolean<> fun(int base) noexcept(p0012) { return {base + 0}; } 65 | Boolean<> cfun(int base) const noexcept(p0012) { return {base + 1}; } 66 | Boolean<> lfun(int base) & noexcept(p0012) { return {base + 2}; } 67 | Boolean<> rfun(int base) && noexcept(p0012) { return {base + 3}; } 68 | Boolean<> clfun(int base) const& noexcept(p0012) { return {base + 4}; } 69 | // gcc finds calls on const rvalues ambiguous up to version 4.8. 70 | #if !defined(__GNUC__) || (__GNUC__ > 4) || \ 71 | ((__GNUC__ == 4) && (__GNUC_MINOR__ > 8)) 72 | Boolean<> crfun(int base) const&& noexcept(p0012) { return {base + 5}; } 73 | #endif 74 | }; 75 | 76 | struct D : C { 77 | D(int val) : C(val) {} 78 | }; 79 | 80 | template 81 | struct smart_ptr { 82 | T* ptr; 83 | smart_ptr(T* ptr) : ptr(ptr) {} 84 | T& operator*() const noexcept(IsNothrow) { return *ptr; } 85 | }; 86 | template 87 | using smart_ptr_throws = smart_ptr; 88 | 89 | std::true_type const nothrows{}; 90 | std::false_type const throws{}; 91 | std::integral_constant const p0012_nothrows{}; 92 | 93 | template 94 | void check_not_fn(R&& r, 95 | std::integral_constant, 96 | F&& nf, 97 | Args&&... args) { 98 | CHECK(std::forward(nf)(std::forward(args)...) == r); 99 | CHECK(std::is_same(nf)(std::forward(args)...)), 100 | R>::value); 101 | CHECK(noexcept(std::forward(nf)(std::forward(args)...)) == 102 | IsNothrow); 103 | } 104 | 105 | TEST_CASE("not_fn(mem-obj-ptr)", "[func.not_fn]") { 106 | auto nf = slb::not_fn(&C::obj); 107 | 108 | /* call wrapper */ { 109 | using call_wrapper = decltype(nf); 110 | 111 | CHECK(std::is_move_constructible::value); 112 | CHECK(std::is_copy_constructible::value); 113 | CHECK(!std::is_move_assignable::value); 114 | CHECK(!std::is_copy_assignable::value); 115 | 116 | CHECK(std::is_nothrow_move_constructible::value); 117 | CHECK(std::is_nothrow_copy_constructible::value); 118 | } 119 | 120 | /* reference */ { 121 | C x = {42}; 122 | C& r = x; 123 | C const& cr = x; 124 | 125 | CHECK_NESTED(not_fn(!r.obj, nothrows, nf, r)); 126 | CHECK_NESTED(not_fn(!cr.obj, nothrows, nf, cr)); 127 | CHECK_NESTED(not_fn(!std::move(r.obj), nothrows, nf, std::move(r))); 128 | CHECK_NESTED(not_fn(!std::move(cr.obj), nothrows, nf, std::move(cr))); 129 | 130 | D d = {42}; 131 | D& rd = d; 132 | D const& crd = d; 133 | 134 | CHECK_NESTED(not_fn(!rd.obj, nothrows, nf, rd)); 135 | CHECK_NESTED(not_fn(!crd.obj, nothrows, nf, crd)); 136 | CHECK_NESTED(not_fn(!std::move(rd.obj), nothrows, nf, std::move(rd))); 137 | CHECK_NESTED(not_fn(!std::move(crd.obj), nothrows, nf, std::move(crd))); 138 | } 139 | 140 | /* reference wrapper */ { 141 | C x = {42}; 142 | std::reference_wrapper r = x; 143 | std::reference_wrapper cr = x; 144 | 145 | CHECK_NESTED(not_fn(!r.get().obj, nothrows, nf, r)); 146 | CHECK_NESTED(not_fn(!cr.get().obj, nothrows, nf, cr)); 147 | } 148 | 149 | /* pointer */ { 150 | C x = {42}; 151 | C* p = &x; 152 | C const* cp = &x; 153 | 154 | CHECK_NESTED(not_fn(!(*p).obj, nothrows, nf, p)); 155 | CHECK_NESTED(not_fn(!(*cp).obj, nothrows, nf, cp)); 156 | } 157 | 158 | /* smart pointer */ { 159 | C x = {42}; 160 | smart_ptr p = &x; 161 | smart_ptr cp = &x; 162 | 163 | CHECK_NESTED(not_fn(!(*p).obj, nothrows, nf, p)); 164 | CHECK_NESTED(not_fn(!(*cp).obj, nothrows, nf, cp)); 165 | 166 | smart_ptr_throws tp = &x; 167 | smart_ptr_throws tcp = &x; 168 | 169 | CHECK_NESTED(not_fn(!(*tp).obj, throws, nf, tp)); 170 | CHECK_NESTED(not_fn(!(*tcp).obj, throws, nf, tcp)); 171 | } 172 | } 173 | 174 | TEST_CASE("not_fn(mem-fun-ptr)", "[func.not_fn]") { 175 | auto nf = slb::not_fn(&C::fun); 176 | 177 | /* call wrapper */ { 178 | using call_wrapper = decltype(nf); 179 | 180 | CHECK(std::is_move_constructible::value); 181 | CHECK(std::is_copy_constructible::value); 182 | CHECK(!std::is_move_assignable::value); 183 | CHECK(!std::is_copy_assignable::value); 184 | 185 | CHECK(std::is_nothrow_move_constructible::value); 186 | CHECK(std::is_nothrow_copy_constructible::value); 187 | } 188 | 189 | auto ncf = slb::not_fn(&C::cfun); 190 | auto nlf = slb::not_fn(&C::lfun); 191 | auto nrf = slb::not_fn(&C::rfun); 192 | auto nclf = slb::not_fn(&C::clfun); 193 | // gcc finds calls on const rvalues ambiguous up to version 4.8. 194 | #if !defined(__GNUC__) || (__GNUC__ > 4) || \ 195 | ((__GNUC__ == 4) && (__GNUC_MINOR__ > 8)) 196 | auto ncrf = slb::not_fn(&C::crfun); 197 | #endif 198 | 199 | /* reference */ { 200 | C x = {42}; 201 | C& r = x; 202 | C const& cr = x; 203 | 204 | CHECK_NESTED(not_fn(!r.fun(40), p0012_nothrows, nf, r, 40)); 205 | CHECK_NESTED(not_fn(!r.cfun(40), p0012_nothrows, ncf, r, 40)); 206 | CHECK_NESTED(not_fn(!r.lfun(40), p0012_nothrows, nlf, r, 40)); 207 | CHECK_NESTED(not_fn(!r.clfun(40), p0012_nothrows, nclf, r, 40)); 208 | 209 | CHECK_NESTED(not_fn(!cr.cfun(40), p0012_nothrows, ncf, cr, 40)); 210 | CHECK_NESTED(not_fn(!cr.clfun(40), p0012_nothrows, nclf, cr, 40)); 211 | 212 | CHECK_NESTED( 213 | not_fn(!std::move(r).fun(40), p0012_nothrows, nf, std::move(r), 40)); 214 | CHECK_NESTED( 215 | not_fn(!std::move(r).cfun(40), p0012_nothrows, ncf, std::move(r), 40)); 216 | CHECK_NESTED(not_fn( 217 | !std::move(r).clfun(40), p0012_nothrows, nclf, std::move(r), 40)); 218 | CHECK_NESTED( 219 | not_fn(!std::move(r).rfun(40), p0012_nothrows, nrf, std::move(r), 40)); 220 | // gcc finds calls on const rvalues ambiguous up to version 4.8. 221 | #if !defined(__GNUC__) || (__GNUC__ > 4) || \ 222 | ((__GNUC__ == 4) && (__GNUC_MINOR__ > 8)) 223 | CHECK_NESTED(not_fn( 224 | !std::move(r).crfun(40), p0012_nothrows, ncrf, std::move(r), 40)); 225 | #endif 226 | 227 | CHECK_NESTED(not_fn( 228 | !std::move(cr).cfun(40), p0012_nothrows, ncf, std::move(cr), 40)); 229 | CHECK_NESTED(not_fn( 230 | !std::move(cr).clfun(40), p0012_nothrows, nclf, std::move(cr), 40)); 231 | // gcc finds calls on const rvalues ambiguous up to version 4.8. 232 | #if !defined(__GNUC__) || (__GNUC__ > 4) || \ 233 | ((__GNUC__ == 4) && (__GNUC_MINOR__ > 8)) 234 | CHECK_NESTED(not_fn( 235 | !std::move(cr).crfun(40), p0012_nothrows, ncrf, std::move(cr), 40)); 236 | #endif 237 | } 238 | 239 | /* reference wrapper */ { 240 | C x = {42}; 241 | std::reference_wrapper r = x; 242 | std::reference_wrapper cr = x; 243 | 244 | CHECK_NESTED(not_fn(!r.get().fun(40), p0012_nothrows, nf, r, 40)); 245 | CHECK_NESTED(not_fn(!r.get().cfun(40), p0012_nothrows, ncf, r, 40)); 246 | CHECK_NESTED(not_fn(!r.get().lfun(40), p0012_nothrows, nlf, r, 40)); 247 | CHECK_NESTED(not_fn(!r.get().clfun(40), p0012_nothrows, nclf, r, 40)); 248 | 249 | CHECK_NESTED(not_fn(!cr.get().cfun(40), p0012_nothrows, ncf, cr, 40)); 250 | CHECK_NESTED(not_fn(!cr.get().clfun(40), p0012_nothrows, nclf, cr, 40)); 251 | } 252 | 253 | /* pointer */ { 254 | C x = {42}; 255 | C* p = &x; 256 | C const* cp = &x; 257 | 258 | CHECK_NESTED(not_fn(!(*p).fun(40), p0012_nothrows, nf, p, 40)); 259 | CHECK_NESTED(not_fn(!(*p).cfun(40), p0012_nothrows, ncf, p, 40)); 260 | CHECK_NESTED(not_fn(!(*p).lfun(40), p0012_nothrows, nlf, p, 40)); 261 | CHECK_NESTED(not_fn(!(*p).clfun(40), p0012_nothrows, nclf, p, 40)); 262 | 263 | CHECK_NESTED(not_fn(!(*cp).cfun(40), p0012_nothrows, ncf, cp, 40)); 264 | CHECK_NESTED(not_fn(!(*cp).clfun(40), p0012_nothrows, nclf, cp, 40)); 265 | } 266 | 267 | /* smart pointer */ { 268 | C x = {42}; 269 | smart_ptr p = &x; 270 | smart_ptr cp = &x; 271 | 272 | CHECK_NESTED(not_fn(!(*p).fun(40), p0012_nothrows, nf, p, 40)); 273 | CHECK_NESTED(not_fn(!(*p).cfun(40), p0012_nothrows, ncf, p, 40)); 274 | CHECK_NESTED(not_fn(!(*p).lfun(40), p0012_nothrows, nlf, p, 40)); 275 | CHECK_NESTED(not_fn(!(*p).clfun(40), p0012_nothrows, nclf, p, 40)); 276 | 277 | CHECK_NESTED(not_fn(!(*cp).cfun(40), p0012_nothrows, ncf, cp, 40)); 278 | CHECK_NESTED(not_fn(!(*cp).clfun(40), p0012_nothrows, nclf, cp, 40)); 279 | 280 | smart_ptr_throws tp = &x; 281 | smart_ptr_throws tcp = &x; 282 | 283 | CHECK_NESTED(not_fn(!(*tp).fun(40), throws, nf, tp, 40)); 284 | CHECK_NESTED(not_fn(!(*tp).cfun(40), throws, ncf, tp, 40)); 285 | CHECK_NESTED(not_fn(!(*tp).lfun(40), throws, nlf, tp, 40)); 286 | CHECK_NESTED(not_fn(!(*tp).clfun(40), throws, nclf, tp, 40)); 287 | 288 | CHECK_NESTED(not_fn(!(*tcp).cfun(40), throws, ncf, tcp, 40)); 289 | CHECK_NESTED(not_fn(!(*tcp).clfun(40), throws, nclf, tcp, 40)); 290 | } 291 | } 292 | 293 | TEST_CASE("not_fn(fun-obj)", "[func.not_fn]") { 294 | /* call wrapper */ { 295 | struct Fn { 296 | Fn() {} 297 | Fn(Fn&&) = default; 298 | Fn(Fn const&) = delete; 299 | Fn& operator=(Fn&&) = default; 300 | void operator()(){}; 301 | }; 302 | using call_wrapper = decltype(slb::not_fn(Fn{})); 303 | 304 | CHECK(std::is_move_constructible::value); 305 | CHECK(!std::is_copy_constructible::value); 306 | CHECK(!std::is_move_assignable::value); 307 | CHECK(!std::is_copy_assignable::value); 308 | 309 | CHECK(std::is_nothrow_move_constructible::value); 310 | } 311 | 312 | /* call-op */ { 313 | struct Fn { 314 | Boolean operator()(int base) & noexcept { return {base + 6}; } 315 | Boolean operator()(int base) const& noexcept { 316 | return {base + 7}; 317 | } 318 | Boolean operator()(int base) && noexcept { return {base + 8}; } 319 | // gcc finds calls on const rvalues ambiguous up to version 4.8. 320 | #if !defined(__GNUC__) || (__GNUC__ > 4) || \ 321 | ((__GNUC__ == 4) && (__GNUC_MINOR__ > 8)) 322 | Boolean operator()(int base) const&& noexcept { 323 | return {base + 9}; 324 | } 325 | #endif 326 | }; 327 | auto f = Fn{}; 328 | auto const& cf = f; 329 | auto nf = slb::not_fn(f); 330 | auto const& ncf = nf; 331 | 332 | CHECK_NESTED(not_fn(!f(40), nothrows, nf, 40)); 333 | CHECK_NESTED(not_fn(!cf(40), nothrows, ncf, 40)); 334 | CHECK_NESTED(not_fn(!std::move(f)(40), nothrows, std::move(nf), 40)); 335 | // gcc finds calls on const rvalues ambiguous up to version 4.8. 336 | #if !defined(__GNUC__) || (__GNUC__ > 4) || \ 337 | ((__GNUC__ == 4) && (__GNUC_MINOR__ > 8)) 338 | CHECK_NESTED(not_fn(!std::move(cf)(40), nothrows, std::move(ncf), 40)); 339 | #endif 340 | } 341 | 342 | /* fun-ptr */ { 343 | struct S { 344 | static Boolean<> f(int base) noexcept(p0012) { return {base + 10}; } 345 | }; 346 | auto f = &S::f; 347 | auto nf = slb::not_fn(f); 348 | 349 | CHECK_NESTED(not_fn(!f(40), p0012_nothrows, nf, 40)); 350 | } 351 | 352 | /* sfinae */ { 353 | struct Fn { 354 | void operator()(int base) = delete; 355 | Boolean<> operator()(int base) const noexcept { return {base + 11}; } 356 | }; 357 | auto f = Fn{}; 358 | auto const& cf = f; 359 | auto nf = slb::not_fn(f); 360 | 361 | CHECK_NESTED(not_fn(!cf(40), nothrows, nf, 40)); 362 | } 363 | } 364 | -------------------------------------------------------------------------------- /test/utility.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SLB.Utility 3 | 4 | Copyright Michael Park, 2017 5 | Copyright Agustin Berge, 2017 6 | 7 | Distributed under the Boost Software License, Version 1.0. 8 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 9 | */ 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "catch.hpp" 18 | 19 | #define CHECK_CXX14_CONSTEXPR(Tag, ...) \ 20 | struct check_cxx14_constexpr_helper_##Tag { \ 21 | static SLB_CXX14_CONSTEXPR bool check(){__VA_ARGS__}; \ 22 | }; \ 23 | SLB_CXX14_CONSTEXPR bool check_cxx14_constexpr_##Tag = \ 24 | check_cxx14_constexpr_helper_##Tag::check(); \ 25 | CHECK(check_cxx14_constexpr_##Tag) 26 | 27 | // [utility.exchange], exchange 28 | 29 | // template 30 | // constexpr T exchange(T& obj, U&& new_val); 31 | TEST_CASE("exchange", "[utility.exchange]") { 32 | struct T { 33 | int val; 34 | T(int val) : val(val) {} 35 | T(T&&) = default; 36 | void operator=(int x) { val = x; } 37 | T& operator=(T&&) = default; 38 | } obj(42); 39 | CHECK(std::is_same::value); 40 | CHECK(slb::exchange(obj, 43).val == 42); 41 | CHECK(slb::exchange(obj, {44}).val == 43); 42 | CHECK(obj.val == 44); 43 | CHECK_CXX14_CONSTEXPR(exchange, { 44 | int obj = 42; 45 | int old_obj = slb::exchange(obj, 43); 46 | return old_obj == 42 && obj == 43; 47 | }); 48 | 49 | /* T old_value = std::move(obj); */ { 50 | struct T { 51 | int val; 52 | T(int val) : val(val) {} 53 | T(T const&) : val(-1) {} 54 | explicit T(T&&) = default; 55 | void operator=(int x) { val = x; } 56 | } obj1(42); 57 | CHECK(slb::exchange(obj1, 43).val == -1); 58 | CHECK(obj1.val == 43); 59 | 60 | /* throws */ { 61 | struct T { 62 | T() {} 63 | T(T const&) { throw 0; } 64 | explicit T(T&&) noexcept = default; 65 | T& operator=(T&&) noexcept = default; 66 | } tobj1; 67 | CHECK_THROWS(slb::exchange(tobj1, {})); 68 | } 69 | } 70 | 71 | /* obj = std::forward(new_val); */ { 72 | struct T { 73 | int val; 74 | T(int val) : val(val) {} 75 | T(T&&) = default; 76 | void operator=(int const& x) { val = x; } 77 | void operator=(int&&) { val = -1; } 78 | } obj2(42); 79 | CHECK(slb::exchange(obj2, 43).val == 42); 80 | CHECK(obj2.val == -1); 81 | 82 | /* throws */ { 83 | struct T { 84 | T() {} 85 | T(T&&) noexcept = default; 86 | T& operator=(T const&) noexcept = default; 87 | T& operator=(T&&) { throw 0; } 88 | } tobj2; 89 | CHECK_THROWS(slb::exchange(tobj2, {})); 90 | } 91 | } 92 | } 93 | 94 | // [forward], forward/move 95 | 96 | // template 97 | // constexpr T&& forward(remove_reference_t& t) noexcept; 98 | // template 99 | // constexpr T&& forward(remove_reference_t&& t) noexcept; 100 | TEST_CASE("forward", "[forward]") { 101 | struct S {}; 102 | 103 | static S s; 104 | static S const cs{}; 105 | 106 | // lvalue -> lvalue 107 | /* type */ { 108 | CHECK(std::is_same(s)), S&>::value); 109 | CHECK(std::is_same(s)), S const&>::value); 110 | CHECK(std::is_same(cs)), S const&>::value); 111 | } 112 | /* `noexcept` */ { 113 | CHECK(noexcept(slb::forward(s))); 114 | CHECK(noexcept(slb::forward(s))); 115 | CHECK(noexcept(slb::forward(cs))); 116 | } 117 | /* C++11 `constexpr` */ { 118 | constexpr S& a = slb::forward(s); 119 | constexpr S const& b = slb::forward(s); 120 | constexpr S const& c = slb::forward(cs); 121 | (void)a; 122 | (void)b; 123 | (void)c; 124 | } 125 | 126 | // lvalue -> rvalue 127 | /* type */ { 128 | CHECK(std::is_same(s)), S&&>::value); 129 | CHECK(std::is_same(s)), S&&>::value); 130 | CHECK(std::is_same(s)), S const&&>::value); 131 | CHECK(std::is_same(s)), S const&&>::value); 132 | CHECK(std::is_same(cs)), S const&&>::value); 133 | CHECK( 134 | std::is_same(cs)), S const&&>::value); 135 | } 136 | /* `noexcept` */ { 137 | CHECK(noexcept(slb::forward(s))); 138 | CHECK(noexcept(slb::forward(s))); 139 | CHECK(noexcept(slb::forward(s))); 140 | CHECK(noexcept(slb::forward(s))); 141 | CHECK(noexcept(slb::forward(cs))); 142 | CHECK(noexcept(slb::forward(cs))); 143 | } 144 | #ifndef _MSC_VER // MSVC doesn't like constexpr rvalue-refs to static variables. 145 | /* C++11 `constexpr` */ { 146 | constexpr S&& a = slb::forward(s); 147 | constexpr S&& b = slb::forward(s); 148 | constexpr S const&& c = slb::forward(s); 149 | constexpr S const&& d = slb::forward(s); 150 | constexpr S const&& e = slb::forward(cs); 151 | constexpr S const&& f = slb::forward(cs); 152 | (void)a; 153 | (void)b; 154 | (void)c; 155 | (void)d; 156 | (void)e; 157 | (void)f; 158 | } 159 | #endif 160 | 161 | // rvalue -> rvalue 162 | struct { 163 | constexpr S operator()() const noexcept { return S{}; } 164 | } make_s; 165 | 166 | struct { 167 | constexpr S const operator()() const noexcept { return S{}; } 168 | } make_cs; 169 | 170 | /* type */ { 171 | CHECK(std::is_same(make_s())), S&&>::value); 172 | CHECK(std::is_same(make_s())), S&&>::value); 173 | CHECK(std::is_same(make_s())), 174 | S const&&>::value); 175 | CHECK(std::is_same(make_s())), 176 | S const&&>::value); 177 | CHECK(std::is_same(make_cs())), 178 | S const&&>::value); 179 | CHECK(std::is_same(make_cs())), 180 | S const&&>::value); 181 | } 182 | /* `noexcept` */ { 183 | CHECK(noexcept(slb::forward(make_s()))); 184 | CHECK(noexcept(slb::forward(make_s()))); 185 | CHECK(noexcept(slb::forward(make_s()))); 186 | CHECK(noexcept(slb::forward(make_s()))); 187 | CHECK(noexcept(slb::forward(make_cs()))); 188 | CHECK(noexcept(slb::forward(make_cs()))); 189 | } 190 | /* C++11 `constexpr` */ { 191 | constexpr S a = slb::forward(make_s()); 192 | constexpr S b = slb::forward(make_s()); 193 | constexpr S c = slb::forward(make_s()); 194 | constexpr S d = slb::forward(make_s()); 195 | constexpr S e = slb::forward(make_cs()); 196 | constexpr S f = slb::forward(make_cs()); 197 | (void)a; 198 | (void)b; 199 | (void)c; 200 | (void)d; 201 | (void)e; 202 | (void)f; 203 | } 204 | 205 | CHECK_CXX14_CONSTEXPR(forward, { 206 | int x = 0; 207 | int const cx = 1; 208 | struct { 209 | constexpr int operator()() const noexcept { return 2; } 210 | } make_x{}; 211 | return slb::forward(x) == 0 && slb::forward(x) == 0 && 212 | slb::forward(cx) == 1 && slb::forward(x) == 0 && 213 | slb::forward(x) == 0 && slb::forward(x) == 0 && 214 | slb::forward(x) == 0 && 215 | slb::forward(cx) == 1 && 216 | slb::forward(cx) == 1 && 217 | slb::forward(make_x()) == 2 && 218 | slb::forward(make_x()) == 2 && 219 | slb::forward(make_x()) == 2 && 220 | slb::forward(make_x()) == 2; 221 | }); 222 | } 223 | 224 | // template 225 | // constexpr remove_reference_t&& move(T&&) noexcept; 226 | TEST_CASE("move", "[forward]") { 227 | struct S {}; 228 | 229 | // lvalue -> rvalue 230 | static S s; 231 | static S const cs{}; 232 | 233 | /* type */ { 234 | CHECK(std::is_same::value); 235 | CHECK(std::is_same::value); 236 | } 237 | /* `noexcept` */ { 238 | CHECK(noexcept(slb::move(s))); 239 | CHECK(noexcept(slb::move(cs))); 240 | } 241 | #ifndef _MSC_VER // MSVC doesn't like constexpr rvalue-refs to static variables. 242 | /* C++11 `constexpr` */ { 243 | constexpr S&& a = slb::move(s); 244 | constexpr S const&& b = slb::move(cs); 245 | (void)a; 246 | (void)b; 247 | } 248 | #endif 249 | 250 | // rvalue -> rvalue 251 | struct { 252 | constexpr S operator()() const noexcept { return S{}; } 253 | } make_s; 254 | 255 | struct { 256 | constexpr S const operator()() const noexcept { return S{}; } 257 | } make_cs; 258 | 259 | /* type */ { 260 | CHECK(std::is_same::value); 261 | CHECK(std::is_same::value); 262 | } 263 | /* `noexcept` */ { 264 | CHECK(noexcept(slb::move(make_s()))); 265 | CHECK(noexcept(slb::move(make_cs()))); 266 | } 267 | /* C++11 `constexpr` */ { 268 | #if __has_warning("-Wpessimizing-move") 269 | #pragma clang diagnostic push 270 | #pragma clang diagnostic ignored "-Wpessimizing-move" 271 | #endif 272 | constexpr S a = slb::move(make_s()); 273 | constexpr S b = slb::move(make_cs()); 274 | #if __has_warning("-Wpessimizing-move") 275 | #pragma clang diagnostic pop 276 | #endif 277 | (void)a; 278 | (void)b; 279 | } 280 | 281 | CHECK_CXX14_CONSTEXPR(move, { 282 | int x = 0; 283 | int const cx = 1; 284 | struct { 285 | constexpr int operator()() const noexcept { return 2; } 286 | } make_x{}; 287 | return slb::move(x) == 0 && slb::move(cx) == 1 && slb::move(make_x()) == 2; 288 | }); 289 | } 290 | 291 | // template 292 | // constexpr conditional_t< 293 | // !is_nothrow_move_constructible_v && is_copy_constructible_v, 294 | // const T&, 295 | // T&&> 296 | // move_if_noexcept(T& x) noexcept; 297 | 298 | template 299 | struct MoveNothrow { 300 | MoveNothrow() = default; 301 | MoveNothrow(MoveNothrow const&) {} 302 | MoveNothrow(MoveNothrow&&) noexcept(IsNothrow) {} 303 | }; 304 | 305 | TEST_CASE("move_if_noexcept", "[forward]") { 306 | struct MoveOnly { 307 | MoveOnly() = default; 308 | MoveOnly(MoveOnly const&) = delete; 309 | MoveOnly(MoveOnly&&) {} 310 | }; 311 | 312 | struct Legacy { 313 | Legacy() = default; 314 | Legacy(Legacy const&) {} 315 | }; 316 | 317 | struct Weird { 318 | Weird() = default; 319 | Weird(Weird const&) {} 320 | Weird(Weird const&&) noexcept {} 321 | }; 322 | 323 | // lvalue -> rvalue 324 | static MoveNothrow mnt; 325 | static MoveOnly mo; 326 | static MoveOnly const cmo{}; 327 | static Weird w{}; 328 | static Weird const cw{}; 329 | 330 | /* type */ { 331 | CHECK(std::is_same&&>::value); 333 | CHECK(std::is_same::value); 334 | CHECK(std::is_same::value); 336 | CHECK(std::is_same::value); 337 | CHECK(std::is_same::value); 339 | } 340 | /* `noexcept` */ { 341 | CHECK(noexcept(slb::move_if_noexcept(mnt))); 342 | CHECK(noexcept(slb::move_if_noexcept(mo))); 343 | CHECK(noexcept(slb::move_if_noexcept(cmo))); 344 | CHECK(noexcept(slb::move_if_noexcept(w))); 345 | CHECK(noexcept(slb::move_if_noexcept(cw))); 346 | } 347 | #ifndef _MSC_VER // MSVC doesn't like constexpr rvalue-refs to static variables. 348 | /* C++11 `constexpr` */ { 349 | constexpr MoveNothrow&& a = slb::move_if_noexcept(mnt); 350 | constexpr MoveOnly&& b = slb::move_if_noexcept(mo); 351 | constexpr MoveOnly const&& c = slb::move_if_noexcept(cmo); 352 | constexpr Weird&& d = slb::move_if_noexcept(w); 353 | constexpr Weird const&& e = slb::move_if_noexcept(cw); 354 | (void)a; 355 | (void)b; 356 | (void)c; 357 | (void)d; 358 | (void)e; 359 | } 360 | #endif 361 | 362 | // lvalue -> lvalue const 363 | static MoveNothrow const cmnt{}; 364 | static MoveNothrow mnf; 365 | static MoveNothrow const cmnf{}; 366 | static Legacy l; 367 | static Legacy const cl{}; 368 | 369 | /* type */ { 370 | CHECK(std::is_same const&>::value); 372 | CHECK(std::is_same const&>::value); 374 | CHECK(std::is_same const&>::value); 376 | CHECK( 377 | std::is_same::value); 378 | CHECK(std::is_same::value); 380 | } 381 | /* `noexcept` */ { 382 | CHECK(noexcept(slb::move_if_noexcept(cmnt))); 383 | CHECK(noexcept(slb::move_if_noexcept(mnf))); 384 | CHECK(noexcept(slb::move_if_noexcept(cmnf))); 385 | CHECK(noexcept(slb::move_if_noexcept(l))); 386 | CHECK(noexcept(slb::move_if_noexcept(cl))); 387 | } 388 | /* C++11 `constexpr` */ { 389 | constexpr MoveNothrow const& a = slb::move_if_noexcept(cmnt); 390 | constexpr MoveNothrow const& b = slb::move_if_noexcept(mnf); 391 | constexpr MoveNothrow const& c = slb::move_if_noexcept(cmnf); 392 | constexpr Legacy const& d = slb::move_if_noexcept(l); 393 | constexpr Legacy const& e = slb::move_if_noexcept(cl); 394 | (void)a; 395 | (void)b; 396 | (void)c; 397 | (void)d; 398 | (void)e; 399 | } 400 | 401 | CHECK_CXX14_CONSTEXPR(move_if_noexcept, { 402 | int x = 0; 403 | int const cx = 1; 404 | return slb::move_if_noexcept(x) == 0 && slb::move_if_noexcept(cx) == 1; 405 | }); 406 | } 407 | 408 | // [utility.as_const], as_const 409 | 410 | // template 411 | // constexpr add_const_t& as_const(T& t) noexcept; 412 | // template 413 | // void as_const(const T&&) = delete; 414 | namespace as_const_deleted { 415 | void as_const(...); 416 | using slb::as_const; 417 | 418 | template 419 | struct no_result : std::true_type {}; 420 | 421 | template 422 | struct no_result())))> 425 | : std::false_type {}; 426 | } // namespace as_const_deleted 427 | 428 | TEST_CASE("as_const", "[utility.as_const]") { 429 | static int t = 42; 430 | CHECK(std::is_same::value); 431 | CHECK(noexcept(slb::as_const(t))); 432 | CHECK(slb::as_const(t) == 42); 433 | constexpr int const& tr = slb::as_const(t); 434 | (void)tr; 435 | CHECK_CXX14_CONSTEXPR(tv, { 436 | int t = 42; 437 | return slb::as_const(t) == t; 438 | }); 439 | 440 | static constexpr int const ct = 42; 441 | CHECK(std::is_same::value); 442 | CHECK(noexcept(slb::as_const(ct))); 443 | CHECK(slb::as_const(ct) == 42); 444 | constexpr int const& ctr = slb::as_const(ct); 445 | constexpr bool ctv = slb::as_const(ct) == ct; 446 | (void)ctr; 447 | (void)ctv; 448 | 449 | using as_const_deleted::no_result; 450 | CHECK(no_result::value); 451 | CHECK(no_result::value); 452 | CHECK_FALSE(no_result::value); 453 | } 454 | 455 | // [intseq], Compile-time integer sequences 456 | 457 | // template 458 | // struct integer_sequence; 459 | #if SLB_INTEGER_SEQUENCE 460 | template 461 | std::size_t deduce_std_integer_sequence(std::integer_sequence) { 462 | return sizeof...(Is); 463 | } 464 | #endif 465 | 466 | TEST_CASE("integer_sequence", "[intseq.intseq]") { 467 | /* using value_type = T; */ { 468 | CHECK(std::is_same::value_type, 469 | int>::value); 470 | } 471 | 472 | /* static constexpr size_t size() noexcept; */ { 473 | using is = slb::integer_sequence; 474 | CHECK(std::is_same::value); 475 | CHECK(noexcept(is::size())); 476 | CHECK(is::size() == 4); 477 | constexpr std::size_t size = is::size(); 478 | (void)size; 479 | } 480 | 481 | /* integer_sequence */ { 482 | slb::integer_sequence bs; 483 | (void)bs; 484 | } 485 | 486 | #if SLB_INTEGER_SEQUENCE 487 | /* std-compatible */ { 488 | slb::integer_sequence slb_is; 489 | std::integer_sequence std_is = slb_is; 490 | (void)std_is; 491 | 492 | CHECK(deduce_std_integer_sequence(slb_is) == 4); 493 | } 494 | #endif 495 | } 496 | 497 | // template 498 | // using index_sequence = integer_sequence; 499 | TEST_CASE("index_sequence", "[utility.syn]") { 500 | CHECK(std::is_same, 501 | slb::integer_sequence>::value); 502 | 503 | CHECK(std::is_same, 504 | slb::integer_sequence>::value); 505 | 506 | CHECK(std::is_same, 507 | slb::integer_sequence>::value); 508 | 509 | CHECK(std::is_same, 510 | slb::integer_sequence>::value); 511 | 512 | #if SLB_INTEGER_SEQUENCE 513 | /* std-compatible */ { 514 | slb::index_sequence<101, 202, 303, 404> slb_is; 515 | std::index_sequence<101, 202, 303, 404> std_is = slb_is; 516 | (void)std_is; 517 | 518 | CHECK(deduce_std_integer_sequence(slb_is) == 4); 519 | } 520 | #endif 521 | } 522 | 523 | // template 524 | // using make_integer_sequence = integer_sequence; 525 | template 526 | void test_make_integer_sequence() { 527 | CHECK(std::is_same, 528 | slb::integer_sequence>::value); 529 | 530 | CHECK(std::is_same, 531 | slb::integer_sequence>::value); 532 | 533 | CHECK(std::is_same, 534 | slb::integer_sequence>::value); 535 | 536 | CHECK(std::is_same, 537 | slb::integer_sequence>::value); 538 | 539 | CHECK(std::is_same, 540 | slb::integer_sequence>::value); 541 | 542 | CHECK(std::is_same, 543 | slb::integer_sequence>::value); 544 | 545 | CHECK(std::is_same, 546 | slb::integer_sequence>::value); 547 | 548 | CHECK(std::is_same, 549 | slb::integer_sequence>::value); 550 | } 551 | 552 | TEST_CASE("make_integer_sequence", "[intseq.make]") { 553 | test_make_integer_sequence(); 554 | test_make_integer_sequence(); 555 | test_make_integer_sequence(); 556 | test_make_integer_sequence(); 557 | test_make_integer_sequence(); 558 | test_make_integer_sequence(); 559 | test_make_integer_sequence(); 560 | test_make_integer_sequence(); 561 | test_make_integer_sequence(); 562 | test_make_integer_sequence(); 563 | test_make_integer_sequence(); 564 | test_make_integer_sequence(); 565 | test_make_integer_sequence(); 566 | test_make_integer_sequence(); 567 | test_make_integer_sequence(); 568 | } 569 | 570 | // template 571 | // using make_index_sequence = make_integer_sequence; 572 | TEST_CASE("make_index_sequence", "[utility.syn]") { 573 | CHECK( 574 | std::is_same, slb::index_sequence<>>::value); 575 | 576 | CHECK( 577 | std::is_same, slb::index_sequence<0>>::value); 578 | 579 | CHECK(std::is_same, 580 | slb::index_sequence<0, 1>>::value); 581 | 582 | CHECK(std::is_same, 583 | slb::index_sequence<0, 1, 2>>::value); 584 | } 585 | 586 | // template 587 | // using index_sequence_for = make_index_sequence; 588 | TEST_CASE("index_sequence_for", "[utility.syn]") { 589 | CHECK(std::is_same, slb::index_sequence<>>::value); 590 | 591 | CHECK(std::is_same, 592 | slb::index_sequence<0>>::value); 593 | 594 | CHECK(std::is_same, 595 | slb::index_sequence<0, 1>>::value); 596 | 597 | CHECK(std::is_same, 598 | slb::index_sequence<0, 1, 2>>::value); 599 | } 600 | --------------------------------------------------------------------------------