104 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// is_invocable_r12 13#include <type_traits>14 15// Non-invocable types16 17static_assert(!std::is_invocable_r_v<void, void>);18static_assert(!std::is_invocable_r_v<void, int>);19static_assert(!std::is_invocable_r_v<void, int*>);20static_assert(!std::is_invocable_r_v<void, int&>);21static_assert(!std::is_invocable_r_v<void, int&&>);22 23// Result type matches24 25template <typename T>26T Return();27 28static_assert(std::is_invocable_r_v<int, decltype(Return<int>)>);29static_assert(std::is_invocable_r_v<char, decltype(Return<char>)>);30static_assert(std::is_invocable_r_v<int*, decltype(Return<int*>)>);31static_assert(std::is_invocable_r_v<int&, decltype(Return<int&>)>);32static_assert(std::is_invocable_r_v<int&&, decltype(Return<int&&>)>);33 34// void result type35 36// Any actual return type should be useable with a result type of void.37static_assert(std::is_invocable_r_v<void, decltype(Return<void>)>);38static_assert(std::is_invocable_r_v<void, decltype(Return<int>)>);39static_assert(std::is_invocable_r_v<void, decltype(Return<int*>)>);40static_assert(std::is_invocable_r_v<void, decltype(Return<int&>)>);41static_assert(std::is_invocable_r_v<void, decltype(Return<int&&>)>);42 43// const- and volatile-qualified void should work too.44static_assert(std::is_invocable_r_v<const void, decltype(Return<void>)>);45static_assert(std::is_invocable_r_v<const void, decltype(Return<int>)>);46static_assert(std::is_invocable_r_v<volatile void, decltype(Return<void>)>);47static_assert(std::is_invocable_r_v<volatile void, decltype(Return<int>)>);48static_assert(std::is_invocable_r_v<const volatile void, decltype(Return<void>)>);49static_assert(std::is_invocable_r_v<const volatile void, decltype(Return<int>)>);50 51// Conversion of result type52 53// It should be possible to use a result type to which the actual return type54// can be converted.55static_assert(std::is_invocable_r_v<char, decltype(Return<int>)>);56static_assert(std::is_invocable_r_v<const int*, decltype(Return<int*>)>);57static_assert(std::is_invocable_r_v<void*, decltype(Return<int*>)>);58static_assert(std::is_invocable_r_v<const int&, decltype(Return<int>)>);59static_assert(std::is_invocable_r_v<const int&, decltype(Return<int&>)>);60static_assert(std::is_invocable_r_v<const int&, decltype(Return<int&&>)>);61static_assert(std::is_invocable_r_v<const char&, decltype(Return<int>)>);62 63// But not a result type where the conversion doesn't work.64static_assert(!std::is_invocable_r_v<int, decltype(Return<void>)>);65static_assert(!std::is_invocable_r_v<int, decltype(Return<int*>)>);66 67// Non-moveable result type68 69// Define a type that can't be move-constructed.70struct CantMove {71 CantMove() = default;72 CantMove(CantMove&&) = delete;73};74 75static_assert(!std::is_move_constructible_v<CantMove>);76static_assert(!std::is_copy_constructible_v<CantMove>);77 78// Define functions that return that type.79CantMove MakeCantMove() { return {}; }80CantMove MakeCantMoveWithArg(int) { return {}; }81 82// Assumption check: it should be possible to call one of those functions and83// use it to initialize a CantMove object.84CantMove cant_move = MakeCantMove();85 86// Therefore std::is_invocable_r should agree that they can be invoked to yield87// a CantMove.88static_assert(std::is_invocable_r_v<CantMove, decltype(MakeCantMove)>);89static_assert(std::is_invocable_r_v<CantMove, decltype(MakeCantMoveWithArg), int>);90 91// Of course it still shouldn't be possible to call one of the functions and get92// back some other type.93static_assert(!std::is_invocable_r_v<int, decltype(MakeCantMove)>);94 95// And the argument types should still be important.96static_assert(!std::is_invocable_r_v<CantMove, decltype(MakeCantMove), int>);97static_assert(!std::is_invocable_r_v<CantMove, decltype(MakeCantMoveWithArg)>);98 99// is_invocable_r100 101// The struct form should be available too, not just the _v variant.102static_assert(std::is_invocable_r<int, decltype(Return<int>)>::value);103static_assert(!std::is_invocable_r<int*, decltype(Return<int>)>::value);104