The exception that I could think of is a "dump memory" function. You take a pointer to something (who cares what it is), and print out the bytes there. That I could see taking a void*.
But that's a really limited case. In general, yes, you do not want to be dealing with blobs of memory as arguments. You want to be dealing with things that are known to be the right kind of thing as arguments.
Anything can be aliased by char, unsigned char, std::byte (as well as signed char in C), and usually uint8_t == unsigned char, thus by extension any valid void pointer can be cast to u8*.
Thus void*+size is usually the right type if ones only care for the memory representation of an object (cstring functions like memcpy, etc.)
With (2) being a wrapper to (1) that compilers will almost always inline, avoiding monomorphization costs (and (2) can also accept rvalues as argument).
(1) could also take std::span<const u8>, but (void*, size) is the more common idiom, more convenient to use and to read , as it is unambiguous which overload it is.
The exception that I could think of is a "dump memory" function. You take a pointer to something (who cares what it is), and print out the bytes there. That I could see taking a void*.
But that's a really limited case. In general, yes, you do not want to be dealing with blobs of memory as arguments. You want to be dealing with things that are known to be the right kind of thing as arguments.