Kokkos Core Kernels Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Kokkos_DetectionIdiom.hpp
1 //@HEADER
2 // ************************************************************************
3 //
4 // Kokkos v. 4.0
5 // Copyright (2022) National Technology & Engineering
6 // Solutions of Sandia, LLC (NTESS).
7 //
8 // Under the terms of Contract DE-NA0003525 with NTESS,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
12 // See https://kokkos.org/LICENSE for license information.
13 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14 //
15 //@HEADER
16 #ifndef KOKKOS_DETECTION_IDIOM_HPP
17 #define KOKKOS_DETECTION_IDIOM_HPP
18 #ifndef KOKKOS_IMPL_PUBLIC_INCLUDE
19 #define KOKKOS_IMPL_PUBLIC_INCLUDE
20 #define KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DETECTIONIDIOM
21 #endif
22 
23 #include <Kokkos_Macros.hpp> // FIXME doesn't actually need it if it wasn't
24  // for the header self-containment test
25 
26 #include <type_traits>
27 
28 // NOTE This header implements the detection idiom from Version 2 of the C++
29 // Extensions for Library Fundamentals, ISO/IEC TS 19568:2017
30 
31 // I deliberately omitted detected_or which does not fit well with the rest
32 // of the specification. In my opinion, it should be removed from the TS.
33 
34 namespace Kokkos {
35 
36 namespace Impl {
37 // base class for nonesuch to inherit from so it is not an aggregate
38 struct nonesuch_base {};
39 
40 // primary template handles all types not supporting the archetypal Op
41 template <class Default, class /*AlwaysVoid*/, template <class...> class Op,
42  class... /*Args*/>
43 struct detector {
44  using value_t = std::false_type;
45  using type = Default;
46 };
47 
48 // specialization recognizes and handles only types supporting Op
49 template <class Default, template <class...> class Op, class... Args>
50 struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> {
51  using value_t = std::true_type;
52  using type = Op<Args...>;
53 };
54 } // namespace Impl
55 
56 struct nonesuch : private Impl::nonesuch_base {
57  ~nonesuch() = delete;
58  nonesuch(nonesuch const&) = delete;
59  void operator=(nonesuch const&) = delete;
60 };
61 
62 template <template <class...> class Op, class... Args>
63 using is_detected =
64  typename Impl::detector<nonesuch, void, Op, Args...>::value_t;
65 
66 template <template <class...> class Op, class... Args>
67 using detected_t = typename Impl::detector<nonesuch, void, Op, Args...>::type;
68 
69 template <class Default, template <class...> class Op, class... Args>
70 using detected_or_t = typename Impl::detector<Default, void, Op, Args...>::type;
71 
72 template <class Expected, template <class...> class Op, class... Args>
73 using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
74 
75 template <class To, template <class...> class Op, class... Args>
76 using is_detected_convertible =
77  std::is_convertible<detected_t<Op, Args...>, To>;
78 
79 template <template <class...> class Op, class... Args>
80 inline constexpr bool is_detected_v = is_detected<Op, Args...>::value;
81 
82 template <class Expected, template <class...> class Op, class... Args>
83 inline constexpr bool is_detected_exact_v =
84  is_detected_exact<Expected, Op, Args...>::value; // NOLINT
85 
86 template <class Expected, template <class...> class Op, class... Args>
87 inline constexpr bool is_detected_convertible_v =
88  is_detected_convertible<Expected, Op, Args...>::value;
89 
90 } // namespace Kokkos
91 
92 #ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DETECTIONIDIOM
93 #undef KOKKOS_IMPL_PUBLIC_INCLUDE
94 #undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_DETECTIONIDIOM
95 #endif
96 #endif