Use `TypeErasedDerefAndApplyToSlotFn` in `NodeHashMapPolicy` and remove `TypeErasedDerefAndApplyToSlotFirstFn`

In `NodeHashMapPolicy::get_hash_slot_fn()`, `pair::first` is at offset 0 of `value_type` when `IsLayoutCompatible<Key, Value>` holds, so `TypeErasedDerefAndApplyToSlotFn<Hash, Key, kIsAbsl, kSeedShift>` can be used directly instead of instantiating a separate `TypeErasedDerefAndApplyToSlotFirstFn<Hash, value_type, kIsAbsl, kSeedShift>` per mapped type `Value`. Delete the now-unused `TypeErasedDerefAndApplyToSlotFirstFn` from `container_memory.h`.

PiperOrigin-RevId: 1009863244
diff --git a/absl/container/internal/container_memory.h b/absl/container/internal/container_memory.h
index 3d16a68..c9dd99d 100644
--- a/absl/container/internal/container_memory.h
+++ b/absl/container/internal/container_memory.h
@@ -637,20 +637,17 @@
 size_t TypeErasedDerefAndApplyToSlotFn(const void* fn, void* slot_ptr,
                                        size_t seed) {
   const auto* f = static_cast<const Fn*>(fn);
-  const T* slot = *static_cast<T**>(slot_ptr);
+  const T* slot;
+  // We use memcpy to avoid a strict-aliasing violation when this is called from
+  // NodeHashMapPolicy::get_hash_slot_fn(). In that case, slot_ptr has type
+  // `std::pair<const T, mapped_type>**`, which is not safe to dereference as
+  // `const T**`. Note that it is safe to dereference `slot` afterwards because
+  // `IsLayoutCompatible` guarantees that `std::pair<const T, mapped_type>` is
+  // standard-layout.
+  std::memcpy(&slot, slot_ptr, sizeof(slot));
   return HashElement<Fn, kIsAbsl, kSeedShift>{*f, seed}(*slot);
 }
 
-// Type erased function to apply `Fn` to data inside of the `slot_ptr->first`.
-// The data is expected to have type `T`.
-template <class Fn, class T, bool kIsAbsl, size_t kSeedShift>
-size_t TypeErasedDerefAndApplyToSlotFirstFn(const void* fn, void* slot_ptr,
-                                            size_t seed) {
-  const auto* f = static_cast<const Fn*>(fn);
-  const T* slot = *static_cast<T**>(slot_ptr);
-  return HashElement<Fn, kIsAbsl, kSeedShift>{*f, seed}(slot->first);
-}
-
 }  // namespace container_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/absl/container/node_hash_map.h b/absl/container/node_hash_map.h
index 4a65ef5..28acb74 100644
--- a/absl/container/node_hash_map.h
+++ b/absl/container/node_hash_map.h
@@ -685,8 +685,8 @@
   template <class Hash, bool kIsAbsl, size_t kSeedShift>
   static constexpr HashSlotFn get_hash_slot_fn() {
     return memory_internal::IsLayoutCompatible<Key, Value>::value
-               ? &TypeErasedDerefAndApplyToSlotFirstFn<Hash, value_type,
-                                                       kIsAbsl, kSeedShift>
+               ? &TypeErasedDerefAndApplyToSlotFn<Hash, Key, kIsAbsl,
+                                                  kSeedShift>
                : nullptr;
   }
 };