104 lines
4.4 KiB
C++
104 lines
4.4 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// UNSUPPORTED: c++03, c++11, c++14
|
|
|
|
// is_invocable_r
|
|
|
|
#include <type_traits>
|
|
|
|
// Non-invocable types
|
|
|
|
static_assert(!std::is_invocable_r<void, void>::value);
|
|
static_assert(!std::is_invocable_r<void, int>::value);
|
|
static_assert(!std::is_invocable_r<void, int*>::value);
|
|
static_assert(!std::is_invocable_r<void, int&>::value);
|
|
static_assert(!std::is_invocable_r<void, int&&>::value);
|
|
|
|
// Result type matches
|
|
|
|
template <typename T>
|
|
T Return();
|
|
|
|
static_assert(std::is_invocable_r<int, decltype(Return<int>)>::value);
|
|
static_assert(std::is_invocable_r<char, decltype(Return<char>)>::value);
|
|
static_assert(std::is_invocable_r<int*, decltype(Return<int*>)>::value);
|
|
static_assert(std::is_invocable_r<int&, decltype(Return<int&>)>::value);
|
|
static_assert(std::is_invocable_r<int&&, decltype(Return<int&&>)>::value);
|
|
|
|
// void result type
|
|
|
|
// Any actual return type should be useable with a result type of void.
|
|
static_assert(std::is_invocable_r<void, decltype(Return<void>)>::value);
|
|
static_assert(std::is_invocable_r<void, decltype(Return<int>)>::value);
|
|
static_assert(std::is_invocable_r<void, decltype(Return<int*>)>::value);
|
|
static_assert(std::is_invocable_r<void, decltype(Return<int&>)>::value);
|
|
static_assert(std::is_invocable_r<void, decltype(Return<int&&>)>::value);
|
|
|
|
// const- and volatile-qualified void should work too.
|
|
static_assert(std::is_invocable_r<const void, decltype(Return<void>)>::value);
|
|
static_assert(std::is_invocable_r<const void, decltype(Return<int>)>::value);
|
|
static_assert(std::is_invocable_r<volatile void, decltype(Return<void>)>::value);
|
|
static_assert(std::is_invocable_r<volatile void, decltype(Return<int>)>::value);
|
|
static_assert(std::is_invocable_r<const volatile void, decltype(Return<void>)>::value);
|
|
static_assert(std::is_invocable_r<const volatile void, decltype(Return<int>)>::value);
|
|
|
|
// Conversion of result type
|
|
|
|
// It should be possible to use a result type to which the actual return type
|
|
// can be converted.
|
|
static_assert(std::is_invocable_r<char, decltype(Return<int>)>::value);
|
|
static_assert(std::is_invocable_r<const int*, decltype(Return<int*>)>::value);
|
|
static_assert(std::is_invocable_r<void*, decltype(Return<int*>)>::value);
|
|
static_assert(std::is_invocable_r<const int&, decltype(Return<int>)>::value);
|
|
static_assert(std::is_invocable_r<const int&, decltype(Return<int&>)>::value);
|
|
static_assert(std::is_invocable_r<const int&, decltype(Return<int&&>)>::value);
|
|
static_assert(std::is_invocable_r<const char&, decltype(Return<int>)>::value);
|
|
|
|
// But not a result type where the conversion doesn't work.
|
|
static_assert(!std::is_invocable_r<int, decltype(Return<void>)>::value);
|
|
static_assert(!std::is_invocable_r<int, decltype(Return<int*>)>::value);
|
|
|
|
// Non-moveable result type
|
|
|
|
// Define a type that can't be move-constructed.
|
|
struct CantMove {
|
|
CantMove() = default;
|
|
CantMove(CantMove&&) = delete;
|
|
};
|
|
|
|
static_assert(!std::is_move_constructible_v<CantMove>);
|
|
static_assert(!std::is_copy_constructible_v<CantMove>);
|
|
|
|
// Define functions that return that type.
|
|
CantMove MakeCantMove() { return {}; }
|
|
CantMove MakeCantMoveWithArg(int) { return {}; }
|
|
|
|
// Assumption check: it should be possible to call one of those functions and
|
|
// use it to initialize a CantMove object.
|
|
CantMove cant_move = MakeCantMove();
|
|
|
|
// Therefore std::is_invocable_r should agree that they can be invoked to yield
|
|
// a CantMove.
|
|
static_assert(std::is_invocable_r<CantMove, decltype(MakeCantMove)>::value);
|
|
static_assert(std::is_invocable_r<CantMove, decltype(MakeCantMoveWithArg), int>::value);
|
|
|
|
// Of course it still shouldn't be possible to call one of the functions and get
|
|
// back some other type.
|
|
static_assert(!std::is_invocable_r<int, decltype(MakeCantMove)>::value);
|
|
|
|
// And the argument types should still be important.
|
|
static_assert(!std::is_invocable_r<CantMove, decltype(MakeCantMove), int>::value);
|
|
static_assert(!std::is_invocable_r<CantMove, decltype(MakeCantMoveWithArg)>::value);
|
|
|
|
// is_invocable_r
|
|
|
|
// The struct form should be available too, not just the _v variant.
|
|
static_assert(std::is_invocable_r<int, decltype(Return<int>)>::value);
|
|
static_assert(!std::is_invocable_r<int*, decltype(Return<int>)>::value);
|