220 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++1410 11// type_traits12 13// is_nothrow_invocable14 15#include <cstddef>16#include <type_traits>17#include <vector>18 19struct Tag {};20 21struct Implicit {22 Implicit(int) noexcept {}23};24 25struct ThrowsImplicit {26 ThrowsImplicit(int) {}27};28 29struct Explicit {30 explicit Explicit(int) noexcept {}31};32 33template <bool IsNoexcept, class Ret, class... Args>34struct CallObject {35 Ret operator()(Args&&...) const noexcept(IsNoexcept);36};37 38struct Sink {39 template <class... Args>40 void operator()(Args&&...) const noexcept {}41};42 43template <class Fn, class... Args>44constexpr bool throws_invocable() {45 return std::is_invocable<Fn, Args...>::value &&46 !std::is_nothrow_invocable<Fn, Args...>::value;47}48 49template <class Ret, class Fn, class... Args>50constexpr bool throws_invocable_r() {51 return std::is_invocable_r<Ret, Fn, Args...>::value &&52 !std::is_nothrow_invocable_r<Ret, Fn, Args...>::value;53}54 55void test_noexcept_function_pointers() {56 struct Dummy {57 void foo() noexcept {}58 static void bar() noexcept {}59 };60 // Check that PMF's and function pointers actually work and that61 // is_nothrow_invocable returns true for noexcept PMF's and function62 // pointers.63 static_assert(std::is_nothrow_invocable<decltype(&Dummy::foo), Dummy&>::value, "");64 static_assert(std::is_nothrow_invocable<decltype(&Dummy::bar)>::value, "");65}66 67int main(int, char**) {68 using AbominableFunc = void(...) const noexcept;69 // Non-callable things70 {71 static_assert(!std::is_nothrow_invocable<void>::value, "");72 static_assert(!std::is_nothrow_invocable<const void>::value, "");73 static_assert(!std::is_nothrow_invocable<volatile void>::value, "");74 static_assert(!std::is_nothrow_invocable<const volatile void>::value, "");75 static_assert(!std::is_nothrow_invocable<std::nullptr_t>::value, "");76 static_assert(!std::is_nothrow_invocable<int>::value, "");77 static_assert(!std::is_nothrow_invocable<double>::value, "");78 79 static_assert(!std::is_nothrow_invocable<int[]>::value, "");80 static_assert(!std::is_nothrow_invocable<int[3]>::value, "");81 82 static_assert(!std::is_nothrow_invocable<int*>::value, "");83 static_assert(!std::is_nothrow_invocable<const int*>::value, "");84 static_assert(!std::is_nothrow_invocable<int const*>::value, "");85 86 static_assert(!std::is_nothrow_invocable<int&>::value, "");87 static_assert(!std::is_nothrow_invocable<const int&>::value, "");88 static_assert(!std::is_nothrow_invocable<int&&>::value, "");89 90 static_assert(!std::is_nothrow_invocable<int, std::vector<int> >::value,91 "");92 static_assert(!std::is_nothrow_invocable<int, std::vector<int*> >::value,93 "");94 static_assert(!std::is_nothrow_invocable<int, std::vector<int**> >::value,95 "");96 97 static_assert(!std::is_nothrow_invocable<AbominableFunc>::value, "");98 99 // with parameters100 static_assert(!std::is_nothrow_invocable<int, int>::value, "");101 static_assert(!std::is_nothrow_invocable<int, double, float>::value, "");102 static_assert(!std::is_nothrow_invocable<int, char, float, double>::value,103 "");104 static_assert(!std::is_nothrow_invocable<Sink, AbominableFunc>::value, "");105 static_assert(!std::is_nothrow_invocable<Sink, void>::value, "");106 static_assert(!std::is_nothrow_invocable<Sink, const volatile void>::value,107 "");108 109 static_assert(!std::is_nothrow_invocable_r<int, void>::value, "");110 static_assert(!std::is_nothrow_invocable_r<int, const void>::value, "");111 static_assert(!std::is_nothrow_invocable_r<int, volatile void>::value, "");112 static_assert(!std::is_nothrow_invocable_r<int, const volatile void>::value,113 "");114 static_assert(!std::is_nothrow_invocable_r<int, std::nullptr_t>::value, "");115 static_assert(!std::is_nothrow_invocable_r<int, int>::value, "");116 static_assert(!std::is_nothrow_invocable_r<int, double>::value, "");117 118 static_assert(!std::is_nothrow_invocable_r<int, int[]>::value, "");119 static_assert(!std::is_nothrow_invocable_r<int, int[3]>::value, "");120 121 static_assert(!std::is_nothrow_invocable_r<int, int*>::value, "");122 static_assert(!std::is_nothrow_invocable_r<int, const int*>::value, "");123 static_assert(!std::is_nothrow_invocable_r<int, int const*>::value, "");124 125 static_assert(!std::is_nothrow_invocable_r<int, int&>::value, "");126 static_assert(!std::is_nothrow_invocable_r<int, const int&>::value, "");127 static_assert(!std::is_nothrow_invocable_r<int, int&&>::value, "");128 129 static_assert(!std::is_nothrow_invocable_r<int, std::vector<int> >::value,130 "");131 static_assert(!std::is_nothrow_invocable_r<int, std::vector<int*> >::value,132 "");133 static_assert(!std::is_nothrow_invocable_r<int, std::vector<int**> >::value,134 "");135 static_assert(!std::is_nothrow_invocable_r<void, AbominableFunc>::value,136 "");137 138 // with parameters139 static_assert(!std::is_nothrow_invocable_r<int, int, int>::value, "");140 static_assert(!std::is_nothrow_invocable_r<int, int, double, float>::value,141 "");142 static_assert(143 !std::is_nothrow_invocable_r<int, int, char, float, double>::value, "");144 static_assert(145 !std::is_nothrow_invocable_r<void, Sink, AbominableFunc>::value, "");146 static_assert(!std::is_nothrow_invocable_r<void, Sink, void>::value, "");147 static_assert(148 !std::is_nothrow_invocable_r<void, Sink, const volatile void>::value,149 "");150 }151 152 {153 // Check that the conversion to the return type is properly checked154 using Fn = CallObject<true, int>;155 static_assert(std::is_nothrow_invocable_r<Implicit, Fn>::value, "");156 static_assert(std::is_nothrow_invocable_r<double, Fn>::value, "");157 static_assert(std::is_nothrow_invocable_r<const volatile void, Fn>::value,158 "");159 static_assert(throws_invocable_r<ThrowsImplicit, Fn>(), "");160 static_assert(!std::is_nothrow_invocable<Fn(), Explicit>(), "");161 }162 {163 // Check that the conversion to the parameters is properly checked164 using Fn = CallObject<true, void, const Implicit&, const ThrowsImplicit&>;165 static_assert(166 std::is_nothrow_invocable<Fn, Implicit&, ThrowsImplicit&>::value, "");167 static_assert(std::is_nothrow_invocable<Fn, int, ThrowsImplicit&>::value,168 "");169 static_assert(throws_invocable<Fn, int, int>(), "");170 static_assert(!std::is_nothrow_invocable<Fn>::value, "");171 }172 {173 // Check that the noexcept-ness of function objects is checked.174 using Fn = CallObject<true, void>;175 using Fn2 = CallObject<false, void>;176 static_assert(std::is_nothrow_invocable<Fn>::value, "");177 static_assert(throws_invocable<Fn2>(), "");178 }179 {180 // Check that PMD derefs are noexcept181 using Fn = int(Tag::*);182 static_assert(std::is_nothrow_invocable<Fn, Tag&>::value, "");183 static_assert(std::is_nothrow_invocable_r<Implicit, Fn, Tag&>::value, "");184 static_assert(throws_invocable_r<ThrowsImplicit, Fn, Tag&>(), "");185 }186 {187 // Check that it's fine if the result type is non-moveable.188 struct CantMove {189 CantMove() = default;190 CantMove(CantMove&&) = delete;191 };192 193 static_assert(!std::is_move_constructible_v<CantMove>);194 static_assert(!std::is_copy_constructible_v<CantMove>);195 196 using Fn = CantMove() noexcept;197 198 static_assert(std::is_nothrow_invocable_r<CantMove, Fn>::value);199 static_assert(!std::is_nothrow_invocable_r<CantMove, Fn, int>::value);200 201 static_assert(std::is_nothrow_invocable_r_v<CantMove, Fn>);202 static_assert(!std::is_nothrow_invocable_r_v<CantMove, Fn, int>);203 }204 {205 // Check for is_nothrow_invocable_v206 using Fn = CallObject<true, int>;207 static_assert(std::is_nothrow_invocable_v<Fn>, "");208 static_assert(!std::is_nothrow_invocable_v<Fn, int>, "");209 }210 {211 // Check for is_nothrow_invocable_r_v212 using Fn = CallObject<true, int>;213 static_assert(std::is_nothrow_invocable_r_v<void, Fn>, "");214 static_assert(!std::is_nothrow_invocable_r_v<int, Fn, int>, "");215 }216 test_noexcept_function_pointers();217 218 return 0;219}220