📌

UE5 C++ で関数テーブル作る[TMap]

に公開

TMap で関数テーブル作りたいときのメモ。

参考:
https://forums.unrealengine.com/t/how-to-build-a-tmap-with-fstring-and-tfunction/437114
https://dexall.co.jp/articles/?p=2065

TFunctionを用いる

// 宣言
TMap<FString, TFunction<int32(int32, int32)>> arithmeticFunctions1; // TFunction 版

// 初期化
arithmeticFunctions1 = {
	{"Add", [this](int a, int b) {return Add(a , b); }} ,
	{"Sub", [this](int a, int b) {return Sub(a , b); }} ,
	{"Mul", [this](int a, int b) {return Mul(a , b); }} ,
	{"Div", [this](int a, int b) {return Div(a , b); }} ,
};

// 呼び出し例
// TFunctioin版の呼び出し
UE_LOG(LogTemp, Log, TEXT("% d"), arithmeticFunctions1["Add"](1, 1));
UE_LOG(LogTemp, Log, TEXT("% d"), arithmeticFunctions1["Sub"](1, 1));
UE_LOG(LogTemp, Log, TEXT("% d"), arithmeticFunctions1["Mul"](1, 1));
UE_LOG(LogTemp, Log, TEXT("% d"), arithmeticFunctions1["Div"](1, 1));
// TFunctioin版の呼び出し(安全)
if (const TFunction<int32(int32, int32)>* func = arithmeticFunctions1.Find("Add")) {
	UE_LOG(LogTemp, Log, TEXT("% d"), (*func)(1, 1));
}

関数ポインタを用いる

// 型定義
using arithmeticFunc = int32(AVRPawn::*) (int32, int32);

// 宣言(今回はstaticメンバを例) 
static TMap<FString, arithmeticFunc> arithmeticFunctions2;	// 関数ポインタ版

// 初期化
TMap<FString, AVRPawn::arithmeticFunc> AVRPawn::arithmeticFunctions2 = {
	{"Add", &AVRPawn::Add},
	{"Sub", &AVRPawn::Sub},
	{"Mul", &AVRPawn::Mul},
	{"Div", &AVRPawn::Div},
};

// 呼び出し例
// 関数ポインタ版の呼び出し
UE_LOG(LogTemp, Log, TEXT("% d"), (this->*arithmeticFunctions2["Add"])(1, 1));
UE_LOG(LogTemp, Log, TEXT("% d"), (this->*arithmeticFunctions2["Sub"])(1, 1));
UE_LOG(LogTemp, Log, TEXT("% d"), (this->*arithmeticFunctions2["Mul"])(1, 1));
UE_LOG(LogTemp, Log, TEXT("% d"), (this->*arithmeticFunctions2["Div"])(1, 1));

// 関数ポインタ版の呼び出し(安全)
if (arithmeticFunc* arithmeticFunction = arithmeticFunctions2.Find("Add")) { // arithmeticFunction は関数ポインタへのポインタ
	UE_LOG(LogTemp, Log, TEXT("%d"), (this->* * arithmeticFunction)(1, 1));
}

コード抜粋

//****************************************
// header
//****************************************
UCLASS()
class AVRPawn : public APawn
{
	GENERATED_BODY()

private:
	using arithmeticFunc = int32(AVRPawn::*) (int32, int32);

	TMap<FString, TFunction<int32(int32, int32)>> arithmeticFunctions1; // TFunction 版
	static TMap<FString, arithmeticFunc> arithmeticFunctions2;			// 関数ポインタ版


public:
	int32 Add(int32 a, int32 b);
	int32 Sub(int32 a, int32 b);
	int32 Mul(int32 a, int32 b);
	int32 Div(int32 a, int32 b);

    AVRPawn();

    void BeginPlay() override;
    
};

//****************************************
// cpp
//****************************************
// 関数ポインタ版の初期化(static)
TMap<FString, AVRPawn::arithmeticFunc> AVRPawn::arithmeticFunctions2 = {
	{"Add", &AVRPawn::Add},
	{"Sub", &AVRPawn::Sub},
	{"Mul", &AVRPawn::Mul},
	{"Div", &AVRPawn::Div},
};

int32 AVRPawn::Add(int32 a, int32 b)
{
	return a + b;
}

int32 AVRPawn::Sub(int32 a, int32 b)
{
	return a - b;
}

int32 AVRPawn::Mul(int32 a, int32 b)
{
	return a * b;
}

int32 AVRPawn::Div(int32 a, int32 b)
{
	return b!=0 ?   a/b: 0;
}

AVRPawn::AVRPawn()
{
	// TFunction版の初期化
	arithmeticFunctions1 = {
		{"Add", [this](int a, int b) {return Add(a , b); }} ,
		{"Sub", [this](int a, int b) {return Sub(a , b); }} ,
		{"Mul", [this](int a, int b) {return Mul(a , b); }} ,
		{"Div", [this](int a, int b) {return Div(a , b); }} ,
    };
}

void AVRPawn::BeginPlay()
{
	// TFunctioin版の呼び出し
	UE_LOG(LogTemp, Log, TEXT("% d"), arithmeticFunctions1["Add"](1, 1));
	UE_LOG(LogTemp, Log, TEXT("% d"), arithmeticFunctions1["Sub"](1, 1));
	UE_LOG(LogTemp, Log, TEXT("% d"), arithmeticFunctions1["Mul"](1, 1));
	UE_LOG(LogTemp, Log, TEXT("% d"), arithmeticFunctions1["Div"](1, 1));
	// TFunctioin版の呼び出し(安全)
	if (const TFunction<int32(int32, int32)>* func = arithmeticFunctions1.Find("Add")) {
		UE_LOG(LogTemp, Log, TEXT("% d"), (*func)(1, 1));
	}

	// 関数ポインタ版の呼び出し
	UE_LOG(LogTemp, Log, TEXT("% d"), (this->*arithmeticFunctions2["Add"])(1, 1));
	UE_LOG(LogTemp, Log, TEXT("% d"), (this->*arithmeticFunctions2["Sub"])(1, 1));
	UE_LOG(LogTemp, Log, TEXT("% d"), (this->*arithmeticFunctions2["Mul"])(1, 1));
	UE_LOG(LogTemp, Log, TEXT("% d"), (this->*arithmeticFunctions2["Div"])(1, 1));

	// 関数ポインタ版の呼び出し(安全)
	if (arithmeticFunc* arithmeticFunction = arithmeticFunctions2.Find("Add")) { 
    // arithmeticFunction は関数ポインタへのポインタ
		UE_LOG(LogTemp, Log, TEXT("%d"), (this->**arithmeticFunction)(1, 1));
	}

}

Discussion