Loading

Logo

Creating Templated Settings

Programming and System Design · 5 minutes Read

An alternative to numerous functions attached to individual components to update user-facing data by using C++ templates.

When creating an array of entries to update properties internally I see tutorials telling developers to add bound buttons and individual getters and setters for each value. In this post I'll try break down how to use templates to automate this process and provide an alternative doesn't requires consistent modifcations when new entries are added.

Part 1: Typenames

A quick way to summarise templating is by breaking down the two different types of typenames. A qualified name is one that defines a scope whereas a dependent requires a template to declare its memory usage. In the example below we create a dependent template and define our data as a parameter.

Here I'm using an FBoolProperty but it works with ints, floats, and even enums.

bool GetProperty(FName name, bool& outValue) const
{
	return GetProperty<FBoolProperty>(name, outValue);
}

These constructors, in the instance above being an FBoolProperty, can then be fed into a templated function and used in creative ways.

Part 2: Templates

Now we can search the property link chain for a value with the name and type we fed through, returning an FProperty pointer that we cast as a PropType to let us get the value inside the container. Next we can get a pointer to that instance in memory by calling ContainerPtrToValuePtr and either copying or setting that address.

template<typename PropType, typename Type>
bool GetProperty(const FName& name, Type& outValue) const
{	
	FProperty* property = propertyStruct.StaticStruct()->FindPropertyByName(name);
	if (PropType* typedProperty = CastField<PropType>(property))
	{
		const void* addr = property->ContainerPtrToValuePtr<void>(&propertyStruct);
		property->CopyCompleteValue(&outValue, addr);
		return true;
	}
	UE_LOG("Could not find entry");
	return false;
}

When compiled Unreal automatically generates functions for each typename, replacing each instance with the real paramter. Now you can create a new function and just replace the Get with Set.

template<typename PropType, typename Type>
bool SetProperty(const FName& name, Type value) const
{	
	FProperty* property = propertyStruct.StaticStruct()->FindPropertyByName(name);
	if (PropType* typedProperty = CastField<PropType>(property))
	{
		property->SetValue_InContainer(&propertyStruct, &value);
		return;
	}
}

And just like that you've reduced a file from a hundred plus lines to these two functions. Depending on how you create and assign these entries (I'd recommend a data asset) you could then pass this system off to a Designer or Artist to create more entries and not even have to touch C++ at all!