#include <cassert>
#include <concepts>
#include <functional>
#include <type_traits>
#include <utility>
template <class R, class F, class ...Args>
concept can_invoke_r = requires {
{ std::invoke_r<R>(std::declval<F>(), std::declval<Args>()...) } -> std::same_as<R>;
};
constexpr bool test() {
{
auto f = [](int i) { return i + 3; };
assert(std::invoke_r<int>(f, 4) == 7);
}
{
auto f = [](int) -> char* { return nullptr; };
static_assert( can_invoke_r<char*, decltype(f), int>);
static_assert( can_invoke_r<void*, decltype(f), int>);
static_assert( can_invoke_r<void, decltype(f), int>);
static_assert(!can_invoke_r<char*, decltype(f), void*>);
static_assert(!can_invoke_r<char*, decltype(f)>);
static_assert(!can_invoke_r<int*, decltype(f), int>);
static_assert(!can_invoke_r<void, decltype(f), void*>);
}
{
auto f = [](int) noexcept(true) -> char* { return nullptr; };
auto g = [](int) noexcept(false) -> char* { return nullptr; };
struct ConversionNotNoexcept {
constexpr ConversionNotNoexcept(char*) noexcept(false) { }
};
static_assert( noexcept(std::invoke_r<char*>(f, 0)));
static_assert(!noexcept(std::invoke_r<char*>(g, 0)));
static_assert(!noexcept(std::invoke_r<ConversionNotNoexcept>(f, 0)));
static_assert(!noexcept(std::invoke_r<ConversionNotNoexcept>(g, 0)));
}
{
auto check = []<class CV_Void> {
bool was_called = false;
auto f = [&](int) -> char* { was_called = true; return nullptr; };
std::invoke_r<CV_Void>(f, 3);
assert(was_called);
static_assert(std::is_void_v<decltype(std::invoke_r<CV_Void>(f, 3))>);
};
check.template operator()<void>();
check.template operator()<void const>();
}
{
struct NonCopyable {
NonCopyable() = default;
NonCopyable(NonCopyable const&) = delete;
NonCopyable(NonCopyable&&) = default;
};
{
bool was_called = false;
auto f = [&](NonCopyable) { was_called = true; };
std::invoke_r<void>(f, NonCopyable());
assert(was_called);
}
{
bool was_called = false;
auto f = [&](NonCopyable) -> int { was_called = true; return 0; };
(void)std::invoke_r<int>(f, NonCopyable());
assert(was_called);
}
{
struct MoveOnlyVoidFunction {
bool& was_called;
constexpr void operator()() && { was_called = true; }
};
bool was_called = false;
std::invoke_r<void>(MoveOnlyVoidFunction{was_called});
assert(was_called);
}
{
struct MoveOnlyIntFunction {
bool& was_called;
constexpr int operator()() && { was_called = true; return 0; }
};
bool was_called = false;
(void)std::invoke_r<int>(MoveOnlyIntFunction{was_called});
assert(was_called);
}
}
{
struct Convertible {
constexpr operator int() const { return 42; }
};
auto f = []() -> Convertible { return Convertible{}; };
int result = std::invoke_r<int>(f);
assert(result == 42);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}