Stroika Library 3.0d16
 
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 template <template <typename...> class Cont, typename... Ts>
38 struct LazyType {
39 using type = Cont<Ts...>;
40 };
41
42 /**
43 * \brief function object whose action is to map its argument, back to the same value it started with (identity function).
44 *
45 * \see also https://stackoverflow.com/questions/41767240/what-is-stdidentity-and-how-it-is-used
46 */
47 struct Identity {
48 using is_transparent = void;
49
50 template <typename T>
51 constexpr T&& operator() (T&& t) const noexcept
52 {
53 return std::forward<T> (t);
54 }
55 };
56
57 namespace Private_ {
58 template <typename T>
59 using BaseDifferenceType_ = decltype (T{} - T{});
60 }
61
62 /**
63 * Computes the difference between two types, plus for enums, returns the difference between the underlying types.
64 *
65 * \par Example Usage
66 * \code
67 * static_assert (same_as<DifferenceType<int>, int>);
68 * static_assert (same_as<DifferenceType<double>, double>);
69 * \endcode
70 */
71 template <typename T>
73
74 /**
75 * Given a type, if there is an unsigned variant of it, convert to that. Works for any type T (and returns T)
76 *
77 * \par Example Usage
78 * \code
79 * static_assert (same_as<UnsignedOfIf<int>, unsigned int>);
80 * static_assert (same_as<UnsignedOfIf<string>, string>);
81 * \endcode
82 *
83 * \note conditional<true, T, T> is a trick similar to LazyType
84 */
85 template <typename T>
86 using UnsignedOfIf = typename conditional_t<is_integral_v<T>, LazyType<make_unsigned_t, T>, conditional<true, T, T>>::type;
87
88 /**
89 * Utility to map from an std::variant<...> and map a TYPE to its underlying index in the given variant
90 *
91 * \note Considered doing this as a function, so could take optional argument and use to figure out
92 * type of VARIANT_VALUE, but frequently used in constexpr setting where this probably would
93 * be helpful (see below example).
94 *
95 * \par Example Usage
96 * \code
97 * variant<filesystem::path, BLOB, String> fSourceData_;
98 * template <typename T>
99 * static constexpr size_t VariantIndex_ = VariantIndex<decltype(fSourceData_), T>;
100 * ...
101 * switch (fSourceData_.index ()) {
102 * case VariantIndex_<filesystem::path>:
103 * case VariantIndex_<BLOB>:
104 * return Streams::BinaryToText::Reader::New (NewReadStream<byte> ());
105 * case VariantIndex_<String>:
106 * return Streams::BinaryToText::Reader::New (get<String> (fSourceData_));
107 * default:
108 * AssertNotReached ();
109 * return {};
110 * }
111 * \endcode
112 */
113 //template <typename VARIANT_VALUE, typename T> // CANNOT figure out how to declare here and define in INL file...
114 //constexpr size_t VariantIndex;
115
116 namespace Private_ {
117 // from https://stackoverflow.com/questions/66254907/parameterize-of-tuple-with-repeated-type
118 template <typename T, typename Seq>
119 struct expander;
120 template <typename T, size_t... Is>
121 struct expander<T, index_sequence<Is...>> {
122 template <typename E, size_t>
123 using elem = E;
124 using type = tuple<elem<T, Is>...>;
125 };
126 template <size_t N, class Type>
127 struct my_tuple {
128 using type = typename expander<Type, make_index_sequence<N>>::type;
129 };
130 }
131
132 /**
133 * \brief same_as<RepeatedTuple_t<3,int>,tuple<int,int,int>>
134 */
135 template <size_t N, class Type>
136 using RepeatedTuple_t = typename Private_::my_tuple<N, Type>::type;
137
138}
139
140/*
141 ********************************************************************************
142 ***************************** Implementation Details ***************************
143 ********************************************************************************
144 */
145#include "TemplateUtilities.inl"
146
147#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...