MCRO
C++23 utilities for Unreal Engine.
Loading...
Searching...
No Matches
TypeName.h
Go to the documentation of this file.
1
/** @noop License Comment
2
* @file
3
* @copyright
4
* This Source Code is subject to the terms of the Mozilla Public License, v2.0.
5
* If a copy of the MPL was not distributed with this file You can obtain one at
6
* https://mozilla.org/MPL/2.0/
7
*
8
* @author David Mórász
9
* @date 2025
10
*/
11
12
/**
13
* @file
14
* Convert types to string
15
*/
16
17
#pragma once
18
19
#include <string>
20
21
#include "CoreMinimal.h"
22
#include "UnrealCtre.h"
23
#include "
Mcro/Text.h
"
24
25
// TODO: C++ 20's std::source_location was used instead of this bouquet of macros, but then some platforms don't have <source_location>
26
#if PLATFORM_LINUX || PLATFORM_ANDROID || PLATFORM_MAC
27
#define PRETTY_FUNC __PRETTY_FUNCTION__
28
#elif PLATFORM_WINDOWS
29
#define PRETTY_FUNC __FUNCSIG__
30
#endif
31
32
// disable this warning to allow us exploit division by zero error in consteval
33
#pragma warning(push)
34
#pragma warning(disable: 4804)
// unsafe use of type 'bool' in operation
35
36
/**
37
* Get a string view of the compile time typename
38
*
39
* @note
40
* Using std::(w)string here instead of FString or FStringView for consteval compatibility
41
*
42
* @tparam T target type
43
* @return string view of the name of the type
44
*/
45
template
<
typename
T>
46
consteval
Mcro::Text::FStdStringView
GetCompileTimeTypeName
()
47
{
48
using namespace
Mcro::Text
;
49
FStdStringView
thisFunctionName { TEXT(PRETTY_FUNC) };
50
51
#if PLATFORM_LINUX || PLATFORM_ANDROID || PLATFORM_MAC
52
53
// on Clang thisFunctionName looks like this:
54
// matching: [--------------------------------------------]
55
// | capturing: [-------------]|
56
// std::string_view GetCompileTimeTypeName() [T = MyTemplate<Vec>]
57
58
// on GCC thisFunctionName has a similar enough format so we can use the same pattern:
59
// matching: [-------------------------------------------------]
60
// | capturing: [-------------]|
61
// consteval std::string_view GetCompileTimeTypeName() [with T = MyTemplate<Vec>; std::string_view = std::basic_string_view<char>]
62
63
auto
result = ctre::search<TEXT(R
"(\s\[(?:with\s)?T\s=\s(?<TYPE>.+?)[;\]])")>(thisFunctionName);
64
65
#elif PLATFORM_WINDOWS
66
67
// on MSVC thisFunctionName looks like this:
68
// matching: [----------------------------------------------------]
69
// | capturing: [---------------------]|
70
// class std::basic_string_view<char,struct std::char_traits<char> > __cdecl GetCompileTimeTypeName<struct MyTemplate<struct Vec>>(void)
71
72
auto
result = ctre::search<TEXT(R
"(GetCompileTimeTypeName<((struct|class)\s)?(?<TYPE>.+?)>\()")>(thisFunctionName);
73
74
#endif
75
76
FStdStringView
output = result.get<TEXT(
"TYPE"
)>().to_view();
77
size_t
size = output.size();
78
size /= output.size() > 0;
// Fail compilation with division-by-zero if we couldn't extract a typename
79
80
return
size ? output :
FStdStringView
();
81
}
82
83
/** Convert types to string */
84
namespace
Mcro::TypeName
85
{
86
using namespace
Mcro::Text
;
87
88
/**
89
* Get a friendly string of an input type without using `typeid(T).name()` Actually this method gives more
90
* predictable results across compilers than `typeid(T).name()` but still not 100% the same. Besides
91
* `TTypeName<T>` can deal with incomplete types as well, whereas `typeid(T)` cannot (more on this in
92
* remarks). While it is more consistent across compilers, it is still not 100% consistent. Take
93
* templated types for instance where MSVC compiler will add "class" prefix in front of type arguments
94
* where GCC or CLang might not. Because of subtle differences like this, it is strongly discouraged to
95
* assume the exact format of the output of `TTypeName<T>`
96
*
97
* Usage:
98
* @code
99
* FStringView myTypeName = TTypeName<FMyType>;
100
* @endcode
101
*
102
* It is useful in templates where a type name should be known in runtime as well. (e.g.: Modular features)
103
*
104
* @remarks
105
* Note on incomplete types: incomplete types on MSVC are localized to current scope. which means
106
* @code
107
* class I;
108
*
109
* class A
110
* {
111
* FStringView GetName() { return TTypeName<I>; }
112
* // Returns "I"
113
* }
114
* @endcode
115
* BUT:
116
* @code
117
* class A
118
* {
119
* FStringView GetName() { return TTypeName<class I>; }
120
* // Returns "A::GetName::I"
121
* }
122
* @endcode
123
* as you can see they are not equal. For sake of simplicity TTypeName only supports incomplete
124
* types when they're declared in global scope. Any other case might yield undesired results
125
* (e.g.: TTypeName<class I> of incomplete `I` might not be the same as TTypeName<I> somewhere
126
* else with `I` being fully defined)
127
*
128
* @tparam T The type to be named
129
*/
130
template
<
typename
T>
131
constexpr
FStringView
TTypeName
= FStringView(
132
GetCompileTimeTypeName
<std::decay_t<T>>().data(),
133
GetCompileTimeTypeName
<std::decay_t<T>>().size()
134
);
135
136
/** @see TTypeName */
137
template
<
typename
T>
138
constexpr
FStdStringView
TTypeNameStd
=
GetCompileTimeTypeName<std::decay_t<T>
>();
139
140
/** @see TTypeName */
141
template
<
typename
T>
142
const
FName
TTypeFName
= FName(
TTypeName<T>
.Len(),
TTypeName<T>
.GetData());
143
144
/** @see TTypeName */
145
template
<
typename
T>
146
const
FString
TTypeString
= FString(
TTypeName<T>
.GetData(),
TTypeName<T>
.Len());
147
}
148
149
#pragma warning(pop)
Text.h
GetCompileTimeTypeName
consteval Mcro::Text::FStdStringView GetCompileTimeTypeName()
Definition
TypeName.h:46
Mcro::Text
Definition
Text.h:20
Mcro::Text::FStdStringView
std::wstring_view FStdStringView
Definition
Text.h:31
Mcro::TypeName
Definition
TypeName.h:85
Mcro::TypeName::TTypeString
const FString TTypeString
Definition
TypeName.h:146
Mcro::TypeName::TTypeName
constexpr FStringView TTypeName
Definition
TypeName.h:131
Mcro::TypeName::TTypeFName
const FName TTypeFName
Definition
TypeName.h:142
Mcro::TypeName::TTypeNameStd
constexpr FStdStringView TTypeNameStd
Definition
TypeName.h:138
Mcro_Origin
Public
Mcro
TypeName.h
Generated by
1.12.0