Skip to content

Commit

Permalink
folly concepts facebook#1 (facebook#2249)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: facebook#2249

We have a need for some common concepts that are used in many places.

This is a proposal, please let me know what you think.

Differential Revision: D59396081
  • Loading branch information
DenisYaroshevskiy authored and facebook-github-bot committed Aug 2, 2024
1 parent 558f312 commit 676f97e
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 5 deletions.
34 changes: 33 additions & 1 deletion folly/Traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,17 @@ struct is_bounded_array : std::bool_constant<is_bounded_array_v<T>> {};

/// is_instantiation_of_v
/// is_instantiation_of
/// instantiated_from
/// uncvref_instantiated_from
///
/// A trait variable and type to check if a given type is an instantiation of a
/// class template.
/// class template. And corresponding concepts.
///
/// Note that this only works with type template parameters. It does not work
/// with non-type template parameters, template template parameters, or alias
/// templates.
///
/// NOTE: there is also `instantiation_of` concept
template <template <typename...> class, typename>
inline constexpr bool is_instantiation_of_v = false;
template <template <typename...> class C, typename... T>
Expand All @@ -174,6 +178,17 @@ template <template <typename...> class C, typename... T>
struct is_instantiation_of
: std::bool_constant<is_instantiation_of_v<C, T...>> {};

#if defined(__cpp_concepts)

template <typename T, template <typename...> class Templ>
concept instantiated_from = is_instantiation_of_v<Templ, T>;

template <typename T, template <typename...> class Templ>
concept uncvref_instantiated_from =
is_instantiation_of_v<Templ, std::remove_cvref_t<T>>;

#endif

/// member_pointer_traits
///
/// For a member-pointer, reveals its constituent member-type and object-type.
Expand Down Expand Up @@ -301,6 +316,23 @@ struct like {
using type = like_t<Src, Dst>;
};

#if defined(__cpp_concepts)

/**
* Concept to check that a type is same as a given type,
* when stripping qualifiers and refernces.
* Especially useful for perfect forwarding of a specific type.
*
* Example:
* ```
* void foo(folly::uncvref_same_as<std::vector<int>> auto&& vec);
* ```
*/
template <typename Ref, typename To>
concept uncvref_same_as = std::is_same_v<std::remove_cvref_t<Ref>, To>;

#endif

/**
* type_t
*
Expand Down
4 changes: 0 additions & 4 deletions folly/test/PortabilityTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,3 @@ TEST(Portability, Final) {
EXPECT_EQ(3, fooBase(p.get()));
EXPECT_EQ(3, fooDerived(p.get()));
}

#if __has_include(<range>)
static_assert(std::ranges::random_access_range<std::vector<int>>);
#endif
40 changes: 40 additions & 0 deletions folly/test/TraitsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,27 @@ TEST(Traits, like) {
value));
}

#if defined(__cpp_concepts)
TEST(Traits, UncvrefSameAs) {
static_assert(folly::uncvref_same_as<std::vector<int>, std::vector<int>>);
static_assert(folly::uncvref_same_as<std::vector<int>&, std::vector<int>>);
static_assert(
folly::uncvref_same_as<const std::vector<int>&, std::vector<int>>);
static_assert(folly::uncvref_same_as<std::vector<int>&&, std::vector<int>>);

constexpr auto refersToExample =
[](folly::uncvref_same_as<std::vector<int>> auto&&) {};

static_assert(std::invocable<decltype(refersToExample), std::vector<int>>);
static_assert(
std::invocable<decltype(refersToExample), const std::vector<int>&>);
static_assert(std::invocable<decltype(refersToExample), std::vector<int>&&>);

static_assert(
!std::invocable<decltype(refersToExample), std::vector<char>&&>);
}
#endif

TEST(Traits, isUnboundedArrayV) {
EXPECT_FALSE((folly::is_unbounded_array_v<void>));
EXPECT_FALSE((folly::is_unbounded_array_v<int>));
Expand All @@ -556,6 +577,25 @@ TEST(Traits, isInstantiationOf) {
EXPECT_FALSE((is_instantiation_of<A, B>::value));
}

#if defined(__cpp_concepts)
TEST(Traits, InstantiationOf) {
static_assert(folly::instantiated_from<A<int>, A>);
static_assert(!folly::instantiated_from<A<int>&, A>);
static_assert(!folly::instantiated_from<A<int>, std::vector>);

static_assert(folly::uncvref_instantiated_from<A<int>, A>);
static_assert(folly::uncvref_instantiated_from<A<int>&, A>);
static_assert(!folly::uncvref_instantiated_from<A<int>&, std::vector>);

auto example = [](folly::uncvref_instantiated_from<std::vector> auto&&) {};

static_assert(std::invocable<decltype(example), std::vector<int>&&>);
static_assert(std::invocable<decltype(example), std::vector<int>&>);
static_assert(std::invocable<decltype(example), const std::vector<int>&>);
static_assert(std::invocable<decltype(example), std::vector<int>>);
}
#endif

TEST(Traits, member_pointer_traits_data) {
struct o {};
using d = float;
Expand Down

0 comments on commit 676f97e

Please sign in to comment.