Skip to content

Instantly share code, notes, and snippets.

@willkill07
Created August 8, 2020 01:26
Show Gist options
  • Save willkill07/2b90a44828e280a0ade65b00b51dfa97 to your computer and use it in GitHub Desktop.
Save willkill07/2b90a44828e280a0ade65b00b51dfa97 to your computer and use it in GitHub Desktop.
#include <type_traits>
template <template <class... Ts> class Name, class ... Args>
struct Concept {
};
template <class> struct CheckConcept;
//#define RAJA_CXX_VERSION 17
#if RAJA_CXX_VERSION >= 17
template <bool, typename ... Cs>
struct AndImpl : std::integral_constant<bool, (CheckConcept<Cs>::value && ...)> {
};
template <bool, typename ... Cs>
struct OrImpl : std::integral_constant<bool, (CheckConcept<Cs>::value || ...)> {
};
#else
template <bool Value, typename...>
struct AndImpl {
static constexpr bool value = Value;
};
template <typename C2, typename ... Rest>
struct AndImpl<true, C2, Rest...> : AndImpl<CheckConcept<C2>::value, Rest...> {
};
template <bool Value, typename...>
struct OrImpl {
static constexpr bool value = Value;
};
template <typename C2, typename ... Rest>
struct OrImpl<false, C2, Rest...> : OrImpl<CheckConcept<C2>::value, Rest...> {
};
#endif
template <bool, typename, typename Else>
struct IfImpl : CheckConcept<Else> {
};
template <typename Then, typename Else>
struct IfImpl<true, Then, Else> : CheckConcept<Then> {
};
template <typename... Args>
struct Cond {
static_assert ((sizeof...(Args) & 1) == 0, "Number of parameters to Cond must be even");
};
template <bool, typename...>
struct CondImpl;
template <typename Concept, typename Next, typename ... Rest>
struct CondImpl<false, Concept, Next, Rest...> : CondImpl<CheckConcept<Next>::value, Rest...> {
};
template <typename Concept, typename ... Rest>
struct CondImpl<true, Concept, Rest...> : CheckConcept<Concept> {
};
template <typename ... C2>
struct And {
static_assert (sizeof...(C2) >= 2, "Number of parameters for Conjunction should be >= 2");
};
template <typename ... C2>
struct Or {
static_assert (sizeof...(C2) >= 2, "Number of parameters for Disjunction should be >= 2");
};
template <typename Cond, typename Then, typename Else>
struct If {
};
template <typename...>
struct true_t {
static constexpr bool value = true;
};
using True = Concept<true_t>;
template <typename...>
struct false_t {
static constexpr bool value = false;
};
using False = Concept<false_t>;
template <class ... Ts>
struct CheckConcept<And<Ts...>> : AndImpl<true, Ts...> {
};
template <class ... Ts>
struct CheckConcept<Or<Ts...>> : AndImpl<false, Ts...> {
};
template <class Cond, class Then, class Else>
struct CheckConcept<If<Cond, Then, Else>> : IfImpl<CheckConcept<Cond>::value, Then, Else> {
};
template <class Test, class Concept, class... Rest>
struct CheckConcept<Cond<Test, Concept, Rest...>> : CondImpl<CheckConcept<Test>::value, Concept, Rest...> {
};
// I really don't want to talk about this, but it's a clever way to
// pack a concept name in a generic wrapper (to potentially take advantage of the
// preprocessor to generate concept definitions). By packing it up, we
// are then able to defer checking to the appropriate time
template <template <class...> class Name,
class ... Args>
struct CheckConcept<Concept<Name, Args...>> {
static constexpr bool value = is_detected_v<Name, Args...>;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment