It depends on what you're trying to do. In general, marshaling everything through void pointers is possible, but it'll cost you in terms of both bug surface (it's much easier to make mistakes when you've opted out of C's weak types) and performance (you now have at least one mandatory pointer indirection, which is especially egregious when your underlying value type is something simple like an integer).
Anything you can do in C++, you can do in C. But C++ compilers will generally optimize semantically equivalent code better than C compilers will, because C++ gives the compiler more freedom.
Another perfectly good solution is to treat a C hashtable as a sort of acceleration index. That C hashtable then, rather than holding pointers simply holds `hashkey -> i` where i is the position into a typed array.
I.e. your data structure is like this:
generic_hashtable Hash; // (hash->int)
Foo *values; // where my typed data is.
Using void* means the compiler (almost certainly?) can’t see through it to optimize. More importantly, it looses you type safety and the self-documentation that flat_hash_map<K, V> gives you.