How do I iterate across a TMap?

This is why you don’t re-invent the wheel.

Iterating across a std::map:

for (auto it = m_map.begin(); it != my_map.end(); ++it)
{
    // it->first is the key, it->second is the value.
}

Iterating across a TMap:

for (auto it = m_map.begin(); it != my_map.end(); ++it)
{
?????
}

Looking in “Containers/Map.h”:

    using PairType = TKeyValuePair<KeyType, ValueType>;
...
    using HashTableType = THashTable<KeyType, PairType, HashTraits, AllocatorType, AllocatorArgsType...>;
    using ConstIterator = typename HashTableType::template Iterator<true>;
    using Iterator = typename HashTableType::template Iterator<false>;

Looking in “Containers/HashTable.h”:

template<class KeyType, class ValueType>
struct TKeyValuePair
{
    KeyType   _Key;
    ValueType _Value;

    bool operator==(const KeyType& Key) const { return _Key == Key; }
    operator const KeyType&() const { return _Key; }
};
...
template<class KeyType, class KeyValueType, class HashTraits, class AllocatorType, typename... AllocatorArgsType>
class THashTable
...
    template <bool bConst>
    class Iterator
    {
    public:
        using iterator_category = std::forward_iterator_tag;
        using value_type = KeyValueType;
...
        template <bool _bConst = bConst>
        ULANG_FORCEINLINE std::enable_if_t<!_bConst, pointer> operator->()
        {
            return _CurrentEntry->_KeyValue;
        }
...
        SEntry* _CurrentEntry;
...
    struct SEntry
    {
        uint32_t  _Hash;  // 0 means unused
        KeyValueType _KeyValue; // Some value, e.g. index into some external array
    };

To put that all together, dereferencing the iterator (operator->) returns _CurrentEntry->_KeyValue which is of type KeyValueType which is actually a TKeyValuePair. So to get the key it should be it→_Key. However when I try that the compiler tells me:

commandlet.cpp:52:96: error: no member named '_Key' in 'TTuple<FString, FString>'
   52 |             UE_LOG(LogOven, Warning, TEXT("Unexpected command line option '%s' found."), *(it->_Key));

But…but…but…the iterator…the code…where did this ■■■■ TTuple come from?

The official documentation ( Map Containers in Unreal Engine | Unreal Engine 5.5 Documentation | Epic Developer Community ) doesn’t even mention the word “iterator”.

So, when iterating across a TMap, how do I extract the key and value from the iterator?

And why don’t Epic document their stupid custom re-implementations of standard containers properly? Actually I know the answer to that. They are too stupid to realise how stupid their API is and that anyone who doesn’t develop it daily might struggle to use it.

I use TTuple to iterate over TMap.

for (const TTuple<[KeyType], [ValueType]> KeyValuePair : MyTMap)
		{
			// KeyValuePair.Key
			// KeyValuePair.Value
		}

:warning: Don’t know if this is the right way to do it, I’m not a programmer :sweat_smile:

I found this guide: TMap in Unreal Engine 5: Ultimate Guide – Unreal C++ API

It seems to agree with you. I don’t know, given my analysis of the relevant header files, why that works. And I really wish they would document it properly.

1 Like

There is a third option that is similar to Arjun’s and not in that linked page:

for (const auto& [Key, Value] : MapInstance)
{
}

The Key and Value variables will be the appropriate types for the TMap and skip the need to involve the Pair at all.