forked from OSchip/llvm-project
[libcxx] adds concepts `std::invocable` and `std::regular_invocable`
Implements parts of: - P0898R3 Standard Library Concepts - P1754 Rename concepts to standard_case for C++20, while we still can Differential Revision: https://reviews.llvm.org/D96235
This commit is contained in:
parent
c63de225fd
commit
17db24a7a8
|
@ -135,7 +135,9 @@ namespace std {
|
|||
*/
|
||||
|
||||
#include <__config>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <version>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
|
@ -216,6 +218,16 @@ concept copy_constructible =
|
|||
constructible_from<_Tp, const _Tp&> && convertible_to<const _Tp&, _Tp> &&
|
||||
constructible_from<_Tp, const _Tp> && convertible_to<const _Tp, _Tp>;
|
||||
|
||||
// [concept.invocable]
|
||||
template<class _Fn, class... _Args>
|
||||
concept invocable = requires(_Fn&& __fn, _Args&&... __args) {
|
||||
_VSTD::invoke(_VSTD::forward<_Fn>(__fn), _VSTD::forward<_Args>(__args)...); // not required to be equality preserving
|
||||
};
|
||||
|
||||
// [concept.regular.invocable]
|
||||
template<class _Fn, class... _Args>
|
||||
concept regular_invocable = invocable<_Fn, _Args...>;
|
||||
|
||||
#endif //_LIBCPP_STD_VER > 17 && defined(__cpp_concepts) && __cpp_concepts >= 201811L
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef CALLABLE_FUNCTIONS_H
|
||||
#define CALLABLE_FUNCTIONS_H
|
||||
|
||||
namespace RegularInvocable {
|
||||
struct A {
|
||||
int I = 13;
|
||||
constexpr int F() const noexcept { return 42; }
|
||||
constexpr int G(int X) { return 2 * X + 1; }
|
||||
constexpr int H(int J) && { return I * J; }
|
||||
};
|
||||
|
||||
constexpr int F() noexcept { return 13; }
|
||||
constexpr int G(int I) { return 2 * I + 1; }
|
||||
} // namespace RegularInvocable
|
||||
|
||||
namespace Predicate {
|
||||
struct L2rSorted {
|
||||
template <class T>
|
||||
constexpr bool operator()(T const& A, T const& B, T const& C) const noexcept {
|
||||
return A <= B && B <= C;
|
||||
}
|
||||
};
|
||||
|
||||
struct NotAPredicate {
|
||||
void operator()() const noexcept {}
|
||||
};
|
||||
} // namespace Predicate
|
||||
|
||||
namespace Relation {
|
||||
int Greater(int X, int Y) noexcept { return X > Y; }
|
||||
} // namespace Relation
|
||||
|
||||
#endif // CALLABLE_FUNCTIONS_H
|
|
@ -0,0 +1,117 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
|
||||
// template<class T, class U>
|
||||
// concept invocable;
|
||||
|
||||
#include <chrono>
|
||||
#include <concepts>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <type_traits>
|
||||
|
||||
#include "functions.h"
|
||||
|
||||
template <class F, class... Args>
|
||||
requires std::invocable<F, Args...> constexpr void
|
||||
ModelsInvocable(F, Args&&...) noexcept{};
|
||||
|
||||
template <class F, class... Args>
|
||||
requires(!std::invocable<F, Args...>) constexpr
|
||||
void NotInvocable(F, Args&&...) noexcept {}
|
||||
|
||||
static_assert(!std::invocable<void>);
|
||||
static_assert(!std::invocable<void*>);
|
||||
static_assert(!std::invocable<int>);
|
||||
static_assert(!std::invocable<int&>);
|
||||
static_assert(!std::invocable<int&&>);
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
using namespace RegularInvocable;
|
||||
|
||||
ModelsInvocable(F);
|
||||
NotInvocable(F, 0);
|
||||
|
||||
ModelsInvocable(G, 2);
|
||||
NotInvocable(G);
|
||||
NotInvocable(G, 3, 0);
|
||||
|
||||
NotInvocable(&A::I);
|
||||
NotInvocable(&A::F);
|
||||
|
||||
{
|
||||
auto X = A{};
|
||||
ModelsInvocable(&A::I, X);
|
||||
ModelsInvocable(&A::F, X);
|
||||
ModelsInvocable(&A::G, X, 0);
|
||||
NotInvocable(&A::G, X);
|
||||
NotInvocable(&A::G, 0);
|
||||
NotInvocable(&A::H);
|
||||
|
||||
auto const& Y = X;
|
||||
ModelsInvocable(&A::I, Y);
|
||||
ModelsInvocable(&A::F, Y);
|
||||
NotInvocable(&A::G, Y, 0);
|
||||
NotInvocable(&A::H, Y, 0);
|
||||
}
|
||||
|
||||
ModelsInvocable(&A::I, A{});
|
||||
ModelsInvocable(&A::F, A{});
|
||||
ModelsInvocable(&A::G, A{}, 0);
|
||||
ModelsInvocable(&A::H, A{}, 0);
|
||||
|
||||
{
|
||||
auto Up = std::make_unique<A>();
|
||||
ModelsInvocable(&A::I, Up);
|
||||
ModelsInvocable(&A::F, Up);
|
||||
ModelsInvocable(&A::G, Up, 0);
|
||||
NotInvocable(&A::H, Up, 0);
|
||||
}
|
||||
{
|
||||
auto Sp = std::make_shared<A>();
|
||||
ModelsInvocable(&A::I, Sp);
|
||||
ModelsInvocable(&A::F, Sp);
|
||||
ModelsInvocable(&A::G, Sp, 0);
|
||||
NotInvocable(&A::H, Sp, 0);
|
||||
}
|
||||
}
|
||||
{
|
||||
using namespace Predicate;
|
||||
{
|
||||
ModelsInvocable(L2rSorted{}, 0, 1, 2);
|
||||
NotInvocable(L2rSorted{});
|
||||
NotInvocable(L2rSorted{}, 0);
|
||||
NotInvocable(L2rSorted{}, 0, 1);
|
||||
}
|
||||
{
|
||||
auto Up = std::make_unique<L2rSorted>();
|
||||
ModelsInvocable(&L2rSorted::operator()<int>, Up, 0, 1, 2);
|
||||
NotInvocable(&L2rSorted::operator()<int>, Up);
|
||||
NotInvocable(&L2rSorted::operator()<int>, Up, 0);
|
||||
NotInvocable(&L2rSorted::operator()<int>, Up, 0, 1);
|
||||
}
|
||||
{
|
||||
auto Sp = std::make_shared<L2rSorted>();
|
||||
ModelsInvocable(&L2rSorted::operator()<int>, Sp, 0, 1, 2);
|
||||
NotInvocable(&L2rSorted::operator()<int>, Sp);
|
||||
NotInvocable(&L2rSorted::operator()<int>, Sp, 0);
|
||||
NotInvocable(&L2rSorted::operator()<int>, Sp, 0, 1);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto G = std::mt19937_64(
|
||||
std::chrono::high_resolution_clock().now().time_since_epoch().count());
|
||||
auto D = std::uniform_int_distribution<>();
|
||||
ModelsInvocable(D, G);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
|
||||
// template<class T, class U>
|
||||
// concept regular_invocable;
|
||||
|
||||
#include <concepts>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <type_traits>
|
||||
|
||||
#include "functions.h"
|
||||
|
||||
template <class F, class... Args>
|
||||
requires std::invocable<F, Args...> constexpr void
|
||||
ModelsRegularInvocable(F, Args&&...) noexcept{};
|
||||
|
||||
template <class F, class... Args>
|
||||
requires(!std::invocable<F, Args...>) constexpr
|
||||
void NotRegularInvocable(F, Args&&...) noexcept {}
|
||||
|
||||
static_assert(!std::invocable<void>);
|
||||
static_assert(!std::invocable<void*>);
|
||||
static_assert(!std::invocable<int>);
|
||||
static_assert(!std::invocable<int&>);
|
||||
static_assert(!std::invocable<int&&>);
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
using namespace RegularInvocable;
|
||||
|
||||
ModelsRegularInvocable(F);
|
||||
NotRegularInvocable(F, 0);
|
||||
|
||||
ModelsRegularInvocable(G, 2);
|
||||
NotRegularInvocable(G);
|
||||
NotRegularInvocable(G, 3, 0);
|
||||
|
||||
NotRegularInvocable(&A::I);
|
||||
NotRegularInvocable(&A::F);
|
||||
|
||||
{
|
||||
auto X = A{};
|
||||
ModelsRegularInvocable(&A::I, X);
|
||||
ModelsRegularInvocable(&A::F, X);
|
||||
ModelsRegularInvocable(&A::G, X, 0);
|
||||
NotRegularInvocable(&A::G, X);
|
||||
NotRegularInvocable(&A::G, 0);
|
||||
NotRegularInvocable(&A::H);
|
||||
|
||||
auto const& Y = X;
|
||||
ModelsRegularInvocable(&A::I, Y);
|
||||
ModelsRegularInvocable(&A::F, Y);
|
||||
NotRegularInvocable(&A::G, Y, 0);
|
||||
NotRegularInvocable(&A::H, Y, 0);
|
||||
}
|
||||
|
||||
ModelsRegularInvocable(&A::I, A{});
|
||||
ModelsRegularInvocable(&A::F, A{});
|
||||
ModelsRegularInvocable(&A::G, A{}, 0);
|
||||
ModelsRegularInvocable(&A::H, A{}, 0);
|
||||
|
||||
{
|
||||
auto Up = std::make_unique<A>();
|
||||
ModelsRegularInvocable(&A::I, Up);
|
||||
ModelsRegularInvocable(&A::F, Up);
|
||||
ModelsRegularInvocable(&A::G, Up, 0);
|
||||
NotRegularInvocable(&A::H, Up, 0);
|
||||
}
|
||||
{
|
||||
auto Sp = std::make_shared<A>();
|
||||
ModelsRegularInvocable(&A::I, Sp);
|
||||
ModelsRegularInvocable(&A::F, Sp);
|
||||
ModelsRegularInvocable(&A::G, Sp, 0);
|
||||
NotRegularInvocable(&A::H, Sp, 0);
|
||||
}
|
||||
}
|
||||
{
|
||||
using namespace Predicate;
|
||||
{
|
||||
ModelsRegularInvocable(L2rSorted{}, 0, 1, 2);
|
||||
NotRegularInvocable(L2rSorted{});
|
||||
NotRegularInvocable(L2rSorted{}, 0);
|
||||
NotRegularInvocable(L2rSorted{}, 0, 1);
|
||||
}
|
||||
{
|
||||
auto Up = std::make_unique<L2rSorted>();
|
||||
ModelsRegularInvocable(&L2rSorted::operator()<int>, Up, 0, 1, 2);
|
||||
NotRegularInvocable(&L2rSorted::operator()<int>, Up);
|
||||
NotRegularInvocable(&L2rSorted::operator()<int>, Up, 0);
|
||||
NotRegularInvocable(&L2rSorted::operator()<int>, Up, 0, 1);
|
||||
}
|
||||
{
|
||||
auto Sp = std::make_shared<L2rSorted>();
|
||||
ModelsRegularInvocable(&L2rSorted::operator()<int>, Sp, 0, 1, 2);
|
||||
NotRegularInvocable(&L2rSorted::operator()<int>, Sp);
|
||||
NotRegularInvocable(&L2rSorted::operator()<int>, Sp, 0);
|
||||
NotRegularInvocable(&L2rSorted::operator()<int>, Sp, 0, 1);
|
||||
}
|
||||
}
|
||||
// {
|
||||
// RNG doesn't model regular_invocable, left here for documentation
|
||||
// auto G = std::mt19937_64(std::random_device()());
|
||||
// auto D = std::uniform_int_distribution<>();
|
||||
// models_invocable(D, G);
|
||||
// }
|
||||
return 0;
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
|
||||
// template<class Derived, class Base>
|
||||
|
|
Loading…
Reference in New Issue