在UE4中,TMap是一個比較常用的容器,TMap的用法很簡單,本文將著重介紹一下TMap如何自定義結構體鍵值。
和眾多Map容器的實現方法類似,TMap也是通過將Key轉換為Hash,來建立對Value的索引,故而想要建立自定義結構體的Key,勢必要確保其可順利轉換為Value。下面是UE4中TMap中關于創建Hash的相關代碼:
/** Defines how the map's pairs are hashed. */
template<typename KeyType, typename ValueType, bool bInAllowDuplicateKeys>
struct TDefaultMapKeyFuncs : BaseKeyFuncs<TPair<KeyType,ValueType>,KeyType,bInAllowDuplicateKeys>
{
typedef typename TTypeTraits<KeyType>::ConstPointerType KeyInitType;
typedef const TPairInitializer<typename TTypeTraits<KeyType>::ConstInitType, typename TTypeTraits<ValueType>::ConstInitType>& ElementInitType;
static FORCEINLINE KeyInitType GetSetKey(ElementInitType Element)
{
return Element.Key;
}
static FORCEINLINE bool Matches(KeyInitType A,KeyInitType B)
{
return A == B;
}
static FORCEINLINE uint32 GetKeyHash(KeyInitType Key)
{
return GetTypeHash(Key);
}
};
其中GetSetKey()用于設置Key的值,Matches()用于進行Key值碰撞測試,GetTypeHash()用于獲取Key的Hash。根據以上代碼不難發現,在生成Hash的時候會會調用Key值結構體的“==”運算符來判斷兩個Key值是否相等,以及GetTypeHash()來產生Hash,由此我們可以得到第一種構建自定義結構體鍵值的方法:
struct FMyKey
{
FString Name;
FString Type;
FORCEINLINE friend bool operator==(const FMyKey& Lhs, const FMyKey& Rhs)
{
return (Lhs.Name == Rhs.Name) && (Lhs.Type == Rhs.Type);
}
};
/** Case insensitive string hash function. */
FORCEINLINE uint32 GetTypeHash(const FMyKey& Key)
{
return HashCombine(GetTypeHash(Key.Name), GetTypeHash(Key.Type));
}
該方法相當于是寫了Key結構體的“==”運算符函數和GetTypeHash函數,它們均為全局函數,這樣可以通過我們定義好的全局函數來生成Hash。
第二種方式就是定義自己的MapKeyFuncs來替代TDefaultMapKeyFuncs,代碼如下:
struct FMyStruct
{
// String which identifies our key
FString UniqueID;
// Some state which doesn't affect struct identity
float SomeFloat;
explicit FMyStruct(float InFloat)
:UniqueID(FGuid::NewGuid().ToString())
, SomeFloat(InFloat)
{
}
};
template <typename ValueType>
struct TMyStructMapKeyFuncs :
BaseKeyFuncs<
TPair<FMyStruct, ValueType>,
FString
>
{
private:
typedef BaseKeyFuncs<
TPair<FMyStruct, ValueType>,
FString
> Super;
public:
typedef typename Super::ElementInitType ElementInitType;
typedef typename Super::KeyInitType KeyInitType;
static KeyInitType GetSetKey(ElementInitType Element)
{
return Element.Key.UniqueID;
}
static bool Matches(KeyInitType A, KeyInitType B)
{
return A.Compare(B, ESearchCase::CaseSensitive) == 0;
}
static uint32 GetKeyHash(KeyInitType Key)
{
return FCrc::StrCrc32(*Key);
}
};
TMap<
FMyStruct,
int32,
FDefaultSetAllocator,
TMyStructMapKeyFuncs<int32>
> MyMapToInt32;
以上是自己在UE4的學習中總結的兩種構造自定義結構體鍵值的方法,希望對大家能有所幫助。
和眾多Map容器的實現方法類似,TMap也是通過將Key轉換為Hash,來建立對Value的索引,故而想要建立自定義結構體的Key,勢必要確保其可順利轉換為Value。下面是UE4中TMap中關于創建Hash的相關代碼:
/** Defines how the map's pairs are hashed. */
template<typename KeyType, typename ValueType, bool bInAllowDuplicateKeys>
struct TDefaultMapKeyFuncs : BaseKeyFuncs<TPair<KeyType,ValueType>,KeyType,bInAllowDuplicateKeys>
{
typedef typename TTypeTraits<KeyType>::ConstPointerType KeyInitType;
typedef const TPairInitializer<typename TTypeTraits<KeyType>::ConstInitType, typename TTypeTraits<ValueType>::ConstInitType>& ElementInitType;
static FORCEINLINE KeyInitType GetSetKey(ElementInitType Element)
{
return Element.Key;
}
static FORCEINLINE bool Matches(KeyInitType A,KeyInitType B)
{
return A == B;
}
static FORCEINLINE uint32 GetKeyHash(KeyInitType Key)
{
return GetTypeHash(Key);
}
};
其中GetSetKey()用于設置Key的值,Matches()用于進行Key值碰撞測試,GetTypeHash()用于獲取Key的Hash。根據以上代碼不難發現,在生成Hash的時候會會調用Key值結構體的“==”運算符來判斷兩個Key值是否相等,以及GetTypeHash()來產生Hash,由此我們可以得到第一種構建自定義結構體鍵值的方法:
struct FMyKey
{
FString Name;
FString Type;
FORCEINLINE friend bool operator==(const FMyKey& Lhs, const FMyKey& Rhs)
{
return (Lhs.Name == Rhs.Name) && (Lhs.Type == Rhs.Type);
}
};
/** Case insensitive string hash function. */
FORCEINLINE uint32 GetTypeHash(const FMyKey& Key)
{
return HashCombine(GetTypeHash(Key.Name), GetTypeHash(Key.Type));
}
該方法相當于是寫了Key結構體的“==”運算符函數和GetTypeHash函數,它們均為全局函數,這樣可以通過我們定義好的全局函數來生成Hash。
第二種方式就是定義自己的MapKeyFuncs來替代TDefaultMapKeyFuncs,代碼如下:
struct FMyStruct
{
// String which identifies our key
FString UniqueID;
// Some state which doesn't affect struct identity
float SomeFloat;
explicit FMyStruct(float InFloat)
:UniqueID(FGuid::NewGuid().ToString())
, SomeFloat(InFloat)
{
}
};
template <typename ValueType>
struct TMyStructMapKeyFuncs :
BaseKeyFuncs<
TPair<FMyStruct, ValueType>,
FString
>
{
private:
typedef BaseKeyFuncs<
TPair<FMyStruct, ValueType>,
FString
> Super;
public:
typedef typename Super::ElementInitType ElementInitType;
typedef typename Super::KeyInitType KeyInitType;
static KeyInitType GetSetKey(ElementInitType Element)
{
return Element.Key.UniqueID;
}
static bool Matches(KeyInitType A, KeyInitType B)
{
return A.Compare(B, ESearchCase::CaseSensitive) == 0;
}
static uint32 GetKeyHash(KeyInitType Key)
{
return FCrc::StrCrc32(*Key);
}
};
TMap<
FMyStruct,
int32,
FDefaultSetAllocator,
TMyStructMapKeyFuncs<int32>
> MyMapToInt32;
以上是自己在UE4的學習中總結的兩種構造自定義結構體鍵值的方法,希望對大家能有所幫助。
參考文獻:https://www.cnblogs.com/pengyingh/articles/5647879.html