前言
之前为了实现一个类似Unity里面DoTween.To的功能,想在参数Tween的过程中将参数更新给委托,实现Tween的过程中委托也执行并传该参数值,为此设计了DECLARE_DELEGATE_OneParam带一个参数的三种委托,分别为了传递float、FVector、FRotator类型的参数,但到最后SetTimer更新模板方法的时候,缺发现委托并不能像之前定义的T模板类型一样传递,为此调研下了下才知道委托也可以用作模板参数,这样我们就将传入的委托类型也设置为模板的形参,在模板展开后,委托调用的时候类型是匹配的就能编译过。
DECLARE_DELEGATE_OneParam(FFloatDelegate, float);
DECLARE_DELEGATE_OneParam(FFVectorDelegate, FVector);
DECLARE_DELEGATE_OneParam(FRotatorDelegate, FRotator);
template<typename TDelegateOneParam,typename T>
void TEST(TDelegateOneParam delegateOneParam, T var) {
if (delegateOneParam.IsBound()) {
delegateOneParam.Execute(var);
}
}
放出代码
#include "DelegateTemplateDistribution.h"
#include <Kismet\KismetSystemLibrary.h>
DECLARE_DELEGATE_OneParam(FFloatDelegate, float);
DECLARE_DELEGATE_OneParam(FFVectorDelegate, FVector);
DECLARE_DELEGATE_OneParam(FRotatorDelegate, FRotator);
template<typename TDelegateOneParam,typename T>
void TEST(TDelegateOneParam delegateOneParam, T var) {
if (delegateOneParam.IsBound()) {
delegateOneParam.Execute(var);
}
}
// Sets default values
ADelegateTemplateDistribution::ADelegateTemplateDistribution()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;
}
// Called when the game starts or when spawned
void ADelegateTemplateDistribution::BeginPlay()
{
Super::BeginPlay();
FFloatDelegate floatDelegate;
floatDelegate.BindUObject(this,&ADelegateTemplateDistribution::FTest);
TEST(floatDelegate,100.0);
FFVectorDelegate vectorDelegate;
TEST(vectorDelegate, FVector::ZeroVector);
FRotatorDelegate rotatorDelegate;
TEST(rotatorDelegate, FRotator::ZeroRotator);
}
// Called every frame
void ADelegateTemplateDistribution::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ADelegateTemplateDistribution::FTest(float f) {
UKismetSystemLibrary::PrintString(GWorld, FString::Printf(TEXT("FTest f = %f"), f));
}
总结
c++模板是编译的时候展开,既然委托传参数量是固定的,加模板参数实际上就是让编译器生成了三个版本的函数,分别对应三种不同类型的委托。只是无法确定参数类型和对应的委托类型,但是只要匹配那展开的代码就能编译过,否则就编译报错。
这是一个非常典型的静态泛型运用场合,让委托类型也作为一个单独的模板形参,就像一个宏展开一样,否则就只能传无参数的委托,要么计算结果得存在外部的成员变量,要么就要用lamba引用捕获一个局部变量,但两个方法都会把这个问题搞复杂。