Stroika Library 3.0d23
 
Loading...
Searching...
No Matches
TemplateUtilities.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Common_TemplateUtilities_h_
5#define _Stroika_Foundation_Common_TemplateUtilities_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <type_traits>
10#include <variant>
11
12#include "Stroika/Foundation/Common/Common.h"
13
14/**
15 * \file
16 *
17 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
18 */
19
21
22 namespace Private_ {
23 struct void_type {
24 using type = void;
25 };
26 }
27
28 /**
29 * Create a singleton of a class initialized once, but whose DTOR is never called.
30 *
31 * Based on template <class _Ty> _Ty& _Immortalize() from VS2k19 runtime library....
32 */
33 template <typename T, typename... ARGS>
34 T& Immortalize (ARGS... args);
35
36 /**
37 * Utility to wrap a class that will not evaluate (illegal) for use with conditional_t (or other similar)
38 * where it wont actually get used, just so it will compile.
39 *
40 * Thanks to https://stackoverflow.com/users/65863/remy-lebeau for idea
41 * See https://stackoverflow.com/questions/65257926/problem-with-false-case-in-conditional-t-being-compiled-and-evaluated
42 *
43 * \note this supports type arguments, but not size_t arguments, which would sometimes be useful too, but cannot see how to mix and match with variadic templates.
44 */
45 template <template <typename...> class Cont, typename... Ts>
46 struct LazyType {
47 using type = Cont<Ts...>;
48 };
49
50 /**
51 * @see LazyType
52 */
53 template <template <typename...> class Cont, typename... Ts>
54 using LazyType_t = typename LazyType<Cont, Ts...>::type;
55
56 /**
57 * \brief Extract the number of arguments, return type, and each individual argument type from a lambda or simple function object.
58 *
59 * \par Example Usage
60 * \code
61 * auto lambda = [](int i) { return long(i*10); };
62 *
63 * using traits = FunctionTraits<decltype(lambda)>;
64 *
65 * static_assert (traits::kArity == 1);
66 * static_assert (same_as<long, traits::result_type>);
67 * static_assert (same_as<int, traits::arg_t<0>>);
68 * \endcode
69 *
70 * CREDITS:
71 * From https://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda
72 * https://stackoverflow.com/users/224671/kennytm
73 *
74 * For generic types, directly use the result of the signature of its 'operator()'
75 * Specialize for pointers to member function
76 *
77 * \note this doesn't work for function objects that have templated operator() - such as String::EqualsComparer, since there is no type to extract.
78 */
79 template <typename T>
80 struct FunctionTraits : public FunctionTraits<decltype (&T::operator())> {};
81 template <typename CLASS_TYPE, typename RETURN_TYPE, typename... ARGS>
82 struct FunctionTraits<RETURN_TYPE (CLASS_TYPE::*) (ARGS...) const> {
83 private:
84 template <size_t i>
85 struct arg_ {
86 using type = typename tuple_element<i, tuple<ARGS...>>::type;
87 };
88 template <size_t i>
89 struct ArgOrVoid_ {
90 using type = typename conditional_t<(i < sizeof...(ARGS)), tuple_element<i, tuple<ARGS...>>, Private_::void_type>::type;
91 };
92
93 public:
94 /**
95 * \brief Number of arguments
96 */
97 static inline constexpr size_t kArity = sizeof...(ARGS);
98
99 public:
100 /**
101 * Function return type.
102 */
103 using result_type = RETURN_TYPE;
104
105 public:
106 /**
107 * @brief Since you cannot use a parameter-pack as type directly, wrap it in a tuple, and then
108 * it can be used (e.g. as KEY in a map).
109 */
110 using args_tuple = tuple<ARGS...>;
111
112 public:
113 /**
114 * @brief Return the ith argument type
115 *
116 * \note UNCLEAR if/how this might work if the function is overloaded...
117 *
118 * \see arg_t, ArgOrVoid_t
119 *
120 * @tparam I
121 */
122 template <size_t I>
123 using arg_t = typename arg_<I>::type;
124
125 public:
126 /**
127 * \brief like 'arg_t' - except that if index > max legal, instead of failing to compile, will return void. Helpful
128 * sometimes in contexts where c++ templates run more code than you might want.
129 */
130 template <size_t I>
131 using ArgOrVoid_t = typename ArgOrVoid_<I>::type;
132 };
133
134 /**
135 * \brief function object whose action is to map its argument, back to the same value it started with (identity function).
136 *
137 * \see also https://stackoverflow.com/questions/41767240/what-is-stdidentity-and-how-it-is-used
138 */
139 struct Identity {
140 using is_transparent = void;
141
142 template <typename T>
143 constexpr T&& operator() (T&& t) const noexcept
144 {
145 return std::forward<T> (t);
146 }
147 };
148
149 namespace Private_ {
150 template <typename T>
151 using BaseDifferenceType_ = decltype (T{} - T{});
152 }
153
154 /**
155 * Computes the difference between two types, plus for enums, returns the difference between the underlying types.
156 *
157 * \par Example Usage
158 * \code
159 * static_assert (same_as<DifferenceType<int>, int>);
160 * static_assert (same_as<DifferenceType<double>, double>);
161 * \endcode
162 */
163 template <typename T>
165
166 /**
167 * Given a type, if there is an unsigned variant of it, convert to that, else value is T. Works for any type T.
168 *
169 * \par Example Usage
170 * \code
171 * static_assert (same_as<UnsignedOfIf<int>, unsigned int>);
172 * static_assert (same_as<UnsignedOfIf<string>, string>);
173 * \endcode
174 *
175 * \note conditional<true, T, T> is a trick similar to LazyType
176 */
177 template <typename T>
178 using UnsignedOfIf = typename conditional_t<is_integral_v<T>, LazyType<make_unsigned_t, T>, conditional<true, T, T>>::type;
179
180 /**
181 * Utility to map from an std::variant<...> and map a TYPE to its underlying index in the given variant
182 *
183 * \note Considered doing this as a function, so could take optional argument and use to figure out
184 * type of VARIANT_VALUE, but frequently used in constexpr setting where this probably would
185 * be helpful (see below example).
186 *
187 * \par Example Usage
188 * \code
189 * variant<filesystem::path, BLOB, String> fSourceData_;
190 * template <typename T>
191 * static constexpr size_t VariantIndex_ = VariantIndex<decltype(fSourceData_), T>;
192 * ...
193 * switch (fSourceData_.index ()) {
194 * case VariantIndex_<filesystem::path>:
195 * case VariantIndex_<BLOB>:
196 * return Streams::BinaryToText::Reader::New (NewReadStream<byte> ());
197 * case VariantIndex_<String>:
198 * return Streams::BinaryToText::Reader::New (get<String> (fSourceData_));
199 * default:
200 * AssertNotReached ();
201 * return {};
202 * }
203 * \endcode
204 */
205 //template <typename VARIANT_VALUE, typename T> // CANNOT figure out how to declare here and define in INL file...
206 //constexpr size_t VariantIndex;
207
208 namespace Private_ {
209 // from https://stackoverflow.com/questions/66254907/parameterize-of-tuple-with-repeated-type
210 template <typename T, typename Seq>
211 struct expander;
212 template <typename T, size_t... Is>
213 struct expander<T, index_sequence<Is...>> {
214 template <typename E, size_t>
215 using elem = E;
216 using type = tuple<elem<T, Is>...>;
217 };
218 template <size_t N, class Type>
219 struct my_tuple {
220 using type = typename expander<Type, make_index_sequence<N>>::type;
221 };
222 }
223
224 /**
225 * \brief same_as<RepeatedTuple_t<3,int>,tuple<int,int,int>>
226 */
227 template <size_t N, class Type>
228 using RepeatedTuple_t = typename Private_::my_tuple<N, Type>::type;
229
230}
231
232/*
233 ********************************************************************************
234 ***************************** Implementation Details ***************************
235 ********************************************************************************
236 */
237#include "TemplateUtilities.inl"
238
239#endif /*_Stroika_Foundation_Common_TemplateUtilities_h_*/
typename LazyType< Cont, Ts... >::type LazyType_t
typename conditional_t< is_integral_v< T >, LazyType< make_unsigned_t, T >, conditional< true, T, T > >::type UnsignedOfIf
typename Private_::my_tuple< N, Type >::type RepeatedTuple_t
same_as<RepeatedTuple_t<3,int>,tuple<int,int,int>>
typename conditional_t< is_enum_v< T >, LazyType< underlying_type_t, T >, LazyType< Private_::BaseDifferenceType_, T > >::type DifferenceType
Extract the number of arguments, return type, and each individual argument type from a lambda or simp...
function object whose action is to map its argument, back to the same value it started with (identity...