Conversion of Enum to String

Hello,
So I have been trying to convert my Enumeration values to an FString.

I followed this post: A new, community-hosted Unreal Engine Wiki - Announcements - Unreal Engine Forums

and ended up with this:

FString getBodyEnumAsString(EBodyPosition value){
	const UEnum* EnumPtr = FindObject<UEnum>(ANY_PACKAGE, TEXT("EBodyPosition"), true);
	if (!EnumPtr) return FString("Invalid");

	return EnumPtr->GetEnumName((int32)value);
}

This is not working though, something about unresolved externals. I am sure I am making some mistake somewhere, and if someone could help me with it, that would be great.

Thanks,

2 Likes

Still being an issue, any help?

I’m doing something similar for one of my enums and it works perfectly fine. Where do you declare the function and how does it get called?

I simply call it when i create my object, by just passing my Enum value through:
getBodyEnumAsString(EBodyPosition::Waist);

something about unresolved externals

would you clarify, is it compilation or run-time issue?

template
FString EnumToString(const FString& enumName, const T value, const FString& defaultValue) const
{
UEnum* pEnum = FindObject(ANY_PACKAGE, *enumName, true);
return pEnum
? ExpandEnumString(pEnum->GetNameByIndex(static_cast(value)).ToString(), enumName)
: defaultValue;
}

FString ExpandEnumString(const FString& name, const FString& enumName)
{
	FString expanded(name);
	FString spaceLetter("");
	FString spaceNumber("");
	FString search("");
	expanded.ReplaceInline(*enumName, TEXT(""), ESearchCase::CaseSensitive);
	expanded.ReplaceInline(TEXT("::"), TEXT(""), ESearchCase::CaseSensitive);
	for (TCHAR letter = 'A'; letter <= 'Z'; ++letter)
	{
		search = FString::Printf(TEXT("%c"), letter);
		spaceLetter = FString::Printf(TEXT(" %c"), letter);
		expanded.ReplaceInline(*search, *spaceLetter, ESearchCase::CaseSensitive);
	}
	for (TCHAR number = '0'; number <= '9'; ++number)
	{
		search = FString::Printf(TEXT("%c"), number);
		spaceNumber = FString::Printf(TEXT(" %c"), number);
		expanded.ReplaceInline(*search, *spaceNumber, ESearchCase::CaseSensitive);
	}
	expanded.ReplaceInline(TEXT("_"), TEXT(" -"), ESearchCase::CaseSensitive);
	expanded = expanded.RightChop(1).Trim().TrimTrailing();
	return expanded;
}

This will work in editor and game modes.

If you’d like to do this without creating a function to convert the enum, here’s a simple way to use the method outlined above:

void AMyGameWeapon::SetWeaponState(EWeaponState::Type NewState)
{
     const UEnum* WeaponStateEnum = FindObject<UEnum>(ANY_PACKAGE, TEXT("EWeaponState"));
     UE_LOG(LogMyGameWeapon, Log, TEXT("SetWeaponState called on weapon %s with state %s (Role %s)")
    		, *GetNameSafe(this)
    		, *(WeaponStateEnum ? WeaponStateEnum->GetEnumName(NewState) : TEXT("<Invalid Enum>"))
    		, *UEnum::GetValueAsString(TEXT("Engine.ENetRole"), Role));

The first line finds a pointer to the enum object from its namespace, and then in the UE_LOG call, we use that enum pointer to get a string value to output. Important to note is that the pointer isn’t guaranteed to be valid, so use a ternary operator to ensure that you safely handle a case where the pointer doesn’t exist.

This UE_LOG statement also supplies an example of grabbing a string from an enum that isn’t enclosed in a namespace and whose path is known.

1 Like

I think this is my first post… had to say… you are a freakin’ wizard. Why is this not in the engine? Thanks!

Using the info from both of these posts I wrote the following function that works:

template<typename T>
static FString EnumToString(const FString& enumName, const T value)
{
	UEnum* pEnum = FindObject<UEnum>(ANY_PACKAGE, *enumName);
	return *(pEnum ? pEnum->GetNameStringByIndex(static_cast<uint8>(value)) : "null");
}

And I just put it in a header file along with my enums. Thanks yall!

For the people that dislike the string parameter, I found a solution to this.
I didn’t like the string because it would present problems when refactoring (renaming) the enum.

#define stringify( name ) # name

UEnum* pEnum = FindObject<UEnum>(ANY_PACKAGE, TEXT(stringify(YourEnumType)), true);

The stringify macro literally converts the characters of its input to chars.
this works great and it will refactor the enum because it’s now used as a type instead of a string.
I hope this helps anyone.

Not working if enum is inside namespace or class.

This is by far the most nice way to deal with Enum stringizing.

As for namespaces enum, you can try to declare using namespace within the implementation body before calling this macro. I’ve seen some usage like this.

namespace SomeNamespace;
{
  enum class EExample 
  {
    X,Y
  }
}

within implementation body

{
  using namespace SomeNamespace;
  stringify(EExample);
}

In addition, one can always write double macro to make it better. This was after referring @MissingAFewHead templated function.

#define stringify(name) #name
#define EnumValStr(Enum, Val)  EnumToString( (stringify(Enum)) , Val)

Please just use:

DEFINE_ENUM_TO_STRING

e.g.

enum EMyEnum
{
}
DEFINE_ENUM_TO_STRING(EMyEnum)

then use

EnumToString(enumValue)
2 Likes

Update: GetEnumName is now deprecated. Use GetNameStringByIndex instead:

static const UEnum* MySpiffyEnumType = FindObject<UEnum>(ANY_PACKAGE, TEXT("EMySpiffyEnum"));
return MySpiffyEnumType->GetNameStringByIndex(static_cast<uint32>(Value));

There’s a fairly simple way to do this that doesn’t require any special definitions.

  • Use FindObject to find a pointer to your enum.

  • Call GetNameStringByIndex() on that pointer.

    static const UEnum* MySpiffyEnumType = FindObject(ANY_PACKAGE, TEXT(“EMySpiffyEnum”));
    UE_LOG(LogTemp, Display, TEXT(“MySpiffyEnum is set to %s”), *(MySpiffyEnumType ? MySpiffyEnumType->GetNameStringByIndex(static_cast(Value)) : TEXT("")));

Throwing my 2 cents here i’ve came with the following:

template<typename T>
static FString EnumToString(T Enum);

It only requires the enum type (absolutely no string and value). It can be used like this:

UYourFunctionLibrary::EnumToString<EBlockMode>(Mode);

Visual studio implementation (in GCC you can use PRETTY_FUNCTION)

template<typename T>
	static FString EnumToString(T Enum)
	{
#if !WITH_EDITOR
		return "";
#else
		static FString EnumName;
		static bool bEnumNameInit = false;

		// Init it once
		if (bEnumNameInit == false)
		{
			bEnumNameInit = true;

			FString FunctionSignature(__FUNCSIG__);
			UE_LOG(LogRPG, Display, TEXT("Enum funcsig: [%s]"), *FunctionSignature);

			int32 FirstIDX = FunctionSignature.Find(TEXT("(enum "), ESearchCase::CaseSensitive, ESearchDir::FromEnd);

			if (FirstIDX != INDEX_NONE)
			{
				FirstIDX = FirstIDX + 6;
				int32 LastIDX = (FunctionSignature.Len() - 1);

				if (FunctionSignature.IsValidIndex(FirstIDX) && FunctionSignature.IsValidIndex(LastIDX) && FirstIDX < LastIDX)
				{
					EnumName = FunctionSignature.Mid(FirstIDX, LastIDX - FirstIDX);
					UE_LOG(LogRPG, Display, TEXT("Enum name: [%s]"), *EnumName);
				}
			}
		}

		if (EnumName.IsEmpty())
			return FString("ENUM_Invalid");
		
		// const UEnum* EnumPtr = FindObject<UEnum>(ANY_PACKAGE, (const TCHAR *)(typeid(T).name()), true);
		const UEnum* EnumPtr = FindObject<UEnum>(ANY_PACKAGE, *EnumName, true);
		if (!EnumPtr)
			return FString("ENUM_Invalid");

		#pragma warning(disable: 4996)
		return EnumPtr->GetDisplayNameText(static_cast<int32>(Enum)).ToString();
#endif
}

I’m sure there’s some template master out there that can transform the usage of FUNCSIG into a constexpr, but the enum name is extracted only once. Note that I’m using it for debugging only, high performance is not a top priority for me.

There’s an extremely easy way to do this now.

I forget what version it came in, I believe it was 4.24 or .23 or sooner.

Check out this file.

Engine\Source\Runtime\CoreUObject\Public\UObject\ReflectedTypeAccessors.h

For enums it goes something like this.

StaticEnum<EnumTypeName>()

that object contains all the methods you need.

You can get all the convert type values you’re looking for.

A common one I use is

StaticEnum<EnumTypeName>()->GetValueAsString( EnumTypeName::EnumOnTheList );
9 Likes

UEnum::GetValueAsName will give you an FName from a UENUM value.

For example:

UE_LOG(LogTemp, Log, TEXT("myenum: %s"), *UEnum::GetValueAsName(DORM_Awake).ToString());

prints:

LogMyRep: myenum: DORM_Awake
22 Likes

This is Awesome! We need to get this moved to the top answer, it worked perfectly for me in 4.26!

1 Like