Passing a Function Pointer as an Argument

Hello,

I’d like to write a simple function for SetTimer with fewer arguments, but I’m having a bit of trouble.

MyAbstractClass.h:

////////////////////////// INCLUDES ////////////////////////

#include "CoreMinimal.h"
#include "UObject/Interface.h"

#include "Engine.h"

//////////////////////// FUNCTIONS ///////////////////////

FTimerHandle IMyStructures::SetTimer(float DelayInterval, bool bLooping,  typename FTimerDelegate::TMethodPtr<UserClass> InTimerMethod) const

MyAbstractClass.cpp:

/////////////////////// INCLUDES //////////////////////////

#include "MyAbstractClass.h"

/////////////////////// FUNCTIONS ///////////////////////

template<class UserClass> 
FTimerHandle IMyStructures::SetTimer(float DelayInterval, bool bLooping,  typename FTimerDelegate::TMethodPtr<UserClass> InTimerMethod) const
{
	FTimerHandle TimerHandle = FTimerHandle();

	if (GetWorld())
	{
		GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, InTimerMethod, DelayInterval, bLooping);
	}

	return TimerHandle;
}

Which, by all accounts should work in theory. But in practice, every time I try to call this new abbreviated function in derived classes like AMyActor.cpp or AMyCharacter.cpp, I get this compiler error:

no instance of function template "AMyActor::SetTimer" matches the argument list. Argument types are: (float, bool, void (AMyActor::*)())

And I’ll get this ugly error unless I declare and define the calling function with a template.

But interestingly enough, if I use the Timer Manager’s SetTimer method:

GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, InTimerMethod, DelayInterval, bLooping);

It compiles without issue, and I don’t need to specify a template as part of the calling function’s signature or definition. Why is the compiler complaining with MY class’s method, but not with the Timer Manager’s method?

Thanks for your time.

Compiler cannot automatically deduce template type (UserClass) from the function pointer alone.

The SetTimer method in TimerManager has an additional UserClass* argument which helps deduction.

You can work around this by expliciting template type when calling

SetTimer<AMyActor>(1.f, false, &AMyActor::Foo);

This will probably still not work, because in your interface function, this is of type IMyStructures. There is an automatic up-casting when calling SetTimer from AMyActor, upcasting from AMyActor to IMyStructures.
However in your template, UserClass is gonna be of type AMyActor. There cannot be automatic downcast of this from IMyStructures to AMyActor so it’s gonna fail there due to mismatch with the method pointer.

You can probably fix it with an explicit cast like this

GetWorld()->GetTimerManager().SetTimer(TimerHandle, (UserClass*)this, InTimerMethod, DelayInterval, bLooping);

I actually tried that before, but the compiler just kept complaining anyways :).

Coming from UE3, I rather enjoyed the simplicity of the timer system. Fewer arguments, roundabout calls to different classes and structs… just less stuff to think about.

But.

I was able to write a macro that FINALLY did the trick:

#define GAME_TIMER(DelayTime, bLooping, FunctionName, Handle)	if (GetWorld()) \
																GetWorld()->GetTimerManager().SetTimer \
																( \
																	Handle, this, FunctionName, \
																	DelayTime, bLooping \
																)

Keeps the simplicity thing going.

(Also, apologies - code doesn’t seem to format very well in the block :-\ )