File indexing completed on 2024-05-19 05:33:32

0001 /*
0002     SPDX-FileCopyrightText: 2018 Ivan Čukić <ivan.cukic(at)kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #ifndef VOY_TRAITS_H
0008 #define VOY_TRAITS_H
0009 
0010 // STL
0011 #include <type_traits>
0012 
0013 // Some meta-programming utility functions and meta-functions,
0014 // including the detection idiom - the poor man's concepts
0015 
0016 #define voy_concept inline constexpr bool
0017 
0018 #define voy_require(Condition) typename std::enable_if_t<Condition, int> = 0
0019 
0020 #define voy_assert_value_type(Type)                                            \
0021     static_assert(std::is_same_v<Type, ::voy::traits::remove_cvref_t<Type>>,   \
0022                   "This needs to be a value type")
0023 
0024 namespace voy::traits {
0025 
0026 // Meta-function to force the compiler to print out the exact type passed
0027 // to it by creating a compilation error because the type is not implemented
0028 template <typename... Types>
0029 struct print_types;
0030 
0031 // Meta-function that always returns false. It is useful for marking a
0032 // particular if-constexpr branch to be erroneous
0033 template <typename T>
0034 voy_concept always_fail = false;
0035 
0036 #define voy_fail(Type, Msg) static_assert(::voy::traits::always_fail<Type>, Msg)
0037 
0038 
0039 // C++20 Stuff
0040 
0041 // Meta-function which strips out the reference and cv qualifiers from the type
0042 template <typename T>
0043 using remove_cvref_t = std::remove_reference_t<std::remove_cv_t<T>>;
0044 
0045 
0046 // The detection idiom -- static introspection made easy
0047 
0048 struct nonesuch {
0049     nonesuch() = delete;
0050     ~nonesuch() = delete;
0051     nonesuch(const nonesuch&) = delete;
0052     nonesuch& operator=(const nonesuch&) = delete;
0053 };
0054 
0055 namespace detail {
0056     template < typename Default
0057              , typename Void
0058              , template <typename...> typename Operation
0059              , typename... Args
0060              >
0061     struct detector {
0062         using value_t = std::false_type;
0063         using type = Default;
0064     };
0065 
0066     template < typename Default
0067              , template <typename...> typename Operation
0068              , typename... Args
0069              >
0070     struct detector < Default
0071                     , std::void_t<Operation<Args...>>
0072                     , Operation
0073                     , Args...
0074                     > {
0075         using value_t = std::true_type;
0076         using type = Operation<Args...>;
0077     };
0078 } // namespace detail
0079 
0080 
0081 template < template <typename...> typename Operation
0082          , typename... Args
0083          >
0084 using is_detected = typename detail::detector < nonesuch
0085                                                , void
0086                                                , Operation
0087                                                , Args...
0088                                                >::value_t;
0089 
0090 
0091 template < template <typename...> typename Operation
0092          , typename... Args
0093          >
0094 voy_concept is_detected_v = is_detected<Operation, Args...>::value;
0095 
0096 
0097 template < template <typename...> typename Operation
0098          , typename... Args
0099          >
0100 using is_detected_t = typename is_detected<Operation, Args...>::type;
0101 
0102 
0103 template < template <typename...> typename Operation
0104          , typename... Args
0105          >
0106 using detected_t = typename detail::detector < nonesuch
0107                                              , void
0108                                              , Operation
0109                                              , Args...>::type;
0110 
0111 
0112 } // namespace voy::traits
0113 
0114 #endif // include guard
0115