Stroika Library 3.0d21
 
Loading...
Searching...
No Matches
TemplateUtilities.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. 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 /**
23 * Create a singleton of a class initialized once, but whose DTOR is never called.
24 *
25 * Based on template <class _Ty> _Ty& _Immortalize() from VS2k19 runtime library....
26 */
27 template <typename T, typename... ARGS>
28 T& Immortalize (ARGS... args);
29
30 /**
31 * Utility to wrap a class that will not evaluate (illegal) for use with conditional_t (or other similar)
32 * where it wont actually get used, just so it will compile.
33 *
34 * Thanks to https://stackoverflow.com/users/65863/remy-lebeau for idea
35 * See https://stackoverflow.com/questions/65257926/problem-with-false-case-in-conditional-t-being-compiled-and-evaluated
36 *
37 * \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.
38 */
39 template <template <typename...> class Cont, typename... Ts>
40 struct LazyType {
41 using type = Cont<Ts...>;
42 };
43
44 /**
45 */
46 template <template <typename...> class Cont, typename... Ts>
47 using LazyType_t = typename LazyType<Cont, Ts...>::type;
48
49 /**
50 * \brief function object whose action is to map its argument, back to the same value it started with (identity function).
51 *
52 * \see also https://stackoverflow.com/questions/41767240/what-is-stdidentity-and-how-it-is-used
53 */
54 struct Identity {
55 using is_transparent = void;
56
57 template <typename T>
58 constexpr T&& operator() (T&& t) const noexcept
59 {
60 return std::forward<T> (t);
61 }
62 };
63
64 namespace Private_ {
65 template <typename T>
66 using BaseDifferenceType_ = decltype (T{} - T{});
67 }
68
69 /**
70 * Computes the difference between two types, plus for enums, returns the difference between the underlying types.
71 *
72 * \par Example Usage
73 * \code
74 * static_assert (same_as<DifferenceType<int>, int>);
75 * static_assert (same_as<DifferenceType<double>, double>);
76 * \endcode
77 */
78 template <typename T>
80
81 /**
82 * Given a type, if there is an unsigned variant of it, convert to that. Works for any type T (and returns T)
83 *
84 * \par Example Usage
85 * \code
86 * static_assert (same_as<UnsignedOfIf<int>, unsigned int>);
87 * static_assert (same_as<UnsignedOfIf<string>, string>);
88 * \endcode
89 *
90 * \note conditional<true, T, T> is a trick similar to LazyType
91 */
92 template <typename T>
93 using UnsignedOfIf = typename conditional_t<is_integral_v<T>, LazyType<make_unsigned_t, T>, conditional<true, T, T>>::type;
94
95 /**
96 * Utility to map from an std::variant<...> and map a TYPE to its underlying index in the given variant
97 *
98 * \note Considered doing this as a function, so could take optional argument and use to figure out
99 * type of VARIANT_VALUE, but frequently used in constexpr setting where this probably would
100 * be helpful (see below example).
101 *
102 * \par Example Usage
103 * \code
104 * variant<filesystem::path, BLOB, String> fSourceData_;
105 * template <typename T>
106 * static constexpr size_t VariantIndex_ = VariantIndex<decltype(fSourceData_), T>;
107 * ...
108 * switch (fSourceData_.index ()) {
109 * case VariantIndex_<filesystem::path>:
110 * case VariantIndex_<BLOB>:
111 * return Streams::BinaryToText::Reader::New (NewReadStream<byte> ());
112 * case VariantIndex_<String>:
113 * return Streams::BinaryToText::Reader::New (get<String> (fSourceData_));
114 * default:
115 * AssertNotReached ();
116 * return {};
117 * }
118 * \endcode
119 */
120 //template <typename VARIANT_VALUE, typename T> // CANNOT figure out how to declare here and define in INL file...
121 //constexpr size_t VariantIndex;
122
123 namespace Private_ {
124 // from https://stackoverflow.com/questions/66254907/parameterize-of-tuple-with-repeated-type
125 template <typename T, typename Seq>
126 struct expander;
127 template <typename T, size_t... Is>
128 struct expander<T, index_sequence<Is...>> {
129 template <typename E, size_t>
130 using elem = E;
131 using type = tuple<elem<T, Is>...>;
132 };
133 template <size_t N, class Type>
134 struct my_tuple {
135 using type = typename expander<Type, make_index_sequence<N>>::type;
136 };
137 }
138
139 /**
140 * \brief same_as<RepeatedTuple_t<3,int>,tuple<int,int,int>>
141 */
142 template <size_t N, class Type>
143 using RepeatedTuple_t = typename Private_::my_tuple<N, Type>::type;
144
145}
146
147/*
148 ********************************************************************************
149 ***************************** Implementation Details ***************************
150 ********************************************************************************
151 */
152#include "TemplateUtilities.inl"
153
154#endif /*_Stroika_Foundation_Common_TemplateUtilities_h_*/
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
function object whose action is to map its argument, back to the same value it started with (identity...