Created
August 8, 2020 01:26
-
-
Save willkill07/2b90a44828e280a0ade65b00b51dfa97 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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