brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.2 KiB · 8a08d36 Raw
140 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++14, c++17, c++2010 11// <functional>12 13// template<class R, class F, class... Args>14// constexpr R invoke_r(F&& f, Args&&... args)              // C++2315//     noexcept(is_nothrow_invocable_r_v<R, F, Args...>);16 17#include <cassert>18#include <concepts>19#include <functional>20#include <type_traits>21#include <utility> // declval22 23template <class R, class F, class ...Args>24concept can_invoke_r = requires {25    { std::invoke_r<R>(std::declval<F>(), std::declval<Args>()...) } -> std::same_as<R>;26};27 28constexpr bool test() {29    // Make sure basic functionality works (i.e. we actually call the function and30    // return the right result).31    {32        auto f = [](int i) { return i + 3; };33        assert(std::invoke_r<int>(f, 4) == 7);34    }35 36    // Make sure invoke_r is SFINAE-friendly37    {38        auto f = [](int) -> char* { return nullptr; };39        static_assert( can_invoke_r<char*, decltype(f), int>);40        static_assert( can_invoke_r<void*, decltype(f), int>);41        static_assert( can_invoke_r<void,  decltype(f), int>);   // discard return type42        static_assert(!can_invoke_r<char*, decltype(f), void*>); // wrong argument type43        static_assert(!can_invoke_r<char*, decltype(f)>);        // missing argument44        static_assert(!can_invoke_r<int*,  decltype(f), int>);   // incompatible return type45        static_assert(!can_invoke_r<void,  decltype(f), void*>); // discard return type, invalid argument type46    }47 48    // Make sure invoke_r has the right noexcept specification49    {50        auto f = [](int) noexcept(true) -> char* { return nullptr; };51        auto g = [](int) noexcept(false) -> char* { return nullptr; };52        struct ConversionNotNoexcept {53            constexpr ConversionNotNoexcept(char*) noexcept(false) { }54        };55        static_assert( noexcept(std::invoke_r<char*>(f, 0)));56        static_assert(!noexcept(std::invoke_r<char*>(g, 0)));                 // function call is not noexcept57        static_assert(!noexcept(std::invoke_r<ConversionNotNoexcept>(f, 0))); // function call is noexcept, conversion isn't58        static_assert(!noexcept(std::invoke_r<ConversionNotNoexcept>(g, 0))); // function call and conversion are both not noexcept59    }60 61    // Make sure invoke_r works with cv-qualified void return type62    {63        auto check = []<class CV_Void> {64            bool was_called = false;65            auto f = [&](int) -> char* { was_called = true; return nullptr; };66            std::invoke_r<CV_Void>(f, 3);67            assert(was_called);68            static_assert(std::is_void_v<decltype(std::invoke_r<CV_Void>(f, 3))>);69        };70        check.template operator()<void>();71        check.template operator()<void const>();72        // volatile void is deprecated, so not testing it73        // const volatile void is deprecated, so not testing it74    }75 76    // Make sure invoke_r forwards its arguments77    {78        struct NonCopyable {79            NonCopyable() = default;80            NonCopyable(NonCopyable const&) = delete;81            NonCopyable(NonCopyable&&) = default;82        };83        // Forward argument, with void return84        {85            bool was_called = false;86            auto f = [&](NonCopyable) { was_called = true; };87            std::invoke_r<void>(f, NonCopyable());88            assert(was_called);89        }90        // Forward argument, with non-void return91        {92            bool was_called = false;93            auto f = [&](NonCopyable) -> int { was_called = true; return 0; };94            (void)std::invoke_r<int>(f, NonCopyable());95            assert(was_called);96        }97        // Forward function object, with void return98        {99            struct MoveOnlyVoidFunction {100                bool& was_called;101                constexpr void operator()() && { was_called = true; }102            };103            bool was_called = false;104            std::invoke_r<void>(MoveOnlyVoidFunction{was_called});105            assert(was_called);106        }107        // Forward function object, with non-void return108        {109            struct MoveOnlyIntFunction {110                bool& was_called;111                constexpr int operator()() && { was_called = true; return 0; }112            };113            bool was_called = false;114            (void)std::invoke_r<int>(MoveOnlyIntFunction{was_called});115            assert(was_called);116        }117    }118 119    // Make sure invoke_r performs an implicit conversion of the result120    {121        struct Convertible {122            constexpr operator int() const { return 42; }123        };124        auto f = []() -> Convertible { return Convertible{}; };125        int result = std::invoke_r<int>(f);126        assert(result == 42);127    }128 129    // Note: We don't test that `std::invoke_r` works with all kinds of callable types here,130    //       since that is extensively tested in the `std::invoke` tests.131 132    return true;133}134 135int main(int, char**) {136    test();137    static_assert(test());138    return 0;139}140