MCRO
C++23 utilities for Unreal Engine.
Loading...
Searching...
No Matches
Types.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#pragma once
13
14#include <string>
15
16#include "CoreMinimal.h"
17#include "Mcro/TypeName.h"
18#include "Mcro/Templates.h"
19
20/** C++ native static reflection utilities, not to be confused with reflection of UObjects */
21namespace Mcro::Types
22{
23 using namespace Mcro::TypeName;
24 using namespace Mcro::Templates;
25
26 class IHaveType;
27
28 template <typename T>
29 concept CHasTypeName = CDerivedFrom<T, IHaveType>;
30
31 /**
32 * A barebones base class for types which may store their type-name as a string
33 *
34 * @todo
35 * C++ 26 has promising proposal for static value-based reflection, which can gather metadata from classes
36 * or even emit them. The best summary I found so far is a stack-overflow answer https://stackoverflow.com/a/77477029
37 * Once that's available we can gather base classes in compile time, and do dynamic casting of objects without
38 * the need for intrusive extra syntax, or extra work at construction.
39 * Currently GCC's `__bases` would be perfect for the job, but other popular compilers don't have similar intrinsics.
40 */
41 class IHaveType : public TSharedFromThis<IHaveType>
42 {
43 public:
44 virtual ~IHaveType() = default;
45
46 protected:
47 FName TypeName;
48
49 /** This function needs to be called on top level derived type for runtime reflection to work */
50 template <typename Self>
51 void SetType(this Self&& self)
52 {
53 self.TypeName = TTypeFName<Self>;
54 }
55
56 public:
57 template <typename Self>
58 using SelfRef = TSharedRef<std::decay_t<Self>>;
59
60 /** Fluent API for setting tpye for deferred initialization (for example in factory functions) */
61 template <typename Self>
62 SelfRef<Self> WithType(this Self&& self)
63 {
64 self.SetType();
65 return SharedThis(&self);
66 }
67
68 FORCEINLINE FName const& GetType() const { return TypeName; }
69
70 /**
71 * Very simple dynamic casting of this object to a derived top-level type.
72 *
73 * @tparam Derived
74 * Only return the desired type when the current object is exactly that type, and doesn't have deeper
75 * inheritance. Proper dynamic casting regarding the entire inheritance tree still without RTTI will come once
76 * proposed C++26 value-typed reflection becomes available.
77 *
78 * @return Object cast to desired type when that's possible (see `Derived`) or nullptr;
79 */
80 template <typename Derived, typename Self>
81 TSharedPtr<Derived> AsExactly(this Self&& self)
82 {
83 if constexpr (CDerivedFrom<Derived, Self>)
84 if (self.TypeName == TTypeFName<Derived>)
85 return StaticCastSharedPtr<Derived>(
86 SharedThis(AsMutablePtr(&self)).ToSharedPtr()
87 );
88 return {};
89 }
90 };
91}
TSharedPtr< Derived > AsExactly(this Self &&self)
Definition Types.h:81
virtual ~IHaveType()=default
void SetType(this Self &&self)
Definition Types.h:51
FORCEINLINE FName const & GetType() const
Definition Types.h:68
SelfRef< Self > WithType(this Self &&self)
Definition Types.h:62
TSharedRef< std::decay_t< Self > > SelfRef
Definition Types.h:58
auto AsMutablePtr(T *input)
Definition Templates.h:101
const FName TTypeFName
Definition TypeName.h:142