As far as I can tell, you don’t need to make the call that way, the template is just one option to spawn actors.
If you look at the engine source (Runtime/Engine/Classes/Engine/World.h) you can see that the template is just a spawn actor call wrapped in a cast template call (CastChecked]:
/** Templated version of SpawnActor that allows you to specify a class type via the template type */
template< class T >
T* SpawnActor( const FActorSpawnParameters& SpawnParameters = FActorSpawnParameters() )
return CastChecked<T>(SpawnActor(T::StaticClass(), NULL, NULL, SpawnParameters),ECastCheckedType::NullAllowed);
You could alternatively make the call directly without the cast like this (Spawning Actors | Unreal Engine Documentation):
AKAsset* SpawnedActor1 = (AKAsset*) GetWorld()->SpawnActor(AKAsset::StaticClass(), NAME_None, &Location);
If you did it this way, you would have different pointer types (AKAsset* in this case) for each different SpawnActor call.
You could do the casting here to avoid that but the CastCheck template has some built in error logging and error checking which is handy.
Therefore, I think the reason this template option is available is to assist with polymorphism in your code.
For example, if you had a base light fixture actor class and you derived a number of subclasses from the base class to add different features, you could use the templated spawn actor code to write spawning functionality that could handle all of the derived classes, in each case returning a base class typed pointer thereby avoiding writing custom code for each subclass.
That is why, referring to the FPS example you mention, where you see ProjectileClass as the first parameter, you often see GetClass(). This enables derived classes to self-identify (lightfixturesubclass1, lightfixturesubclass2, etc) while returning in all cases a pointer of lightfixturebaseclass type.