| > void DoSomething(const void* p, size_t numBytes) would be something like template <typename T>
void DoSomething (const T& ref) or void DoSomething(const T& ref, size_t numBytes) or C++20-y void DoSomething (const auto& ref) If the class you're passing in already qualifies a size like member fn,
template<typename T> requires requires(T t){ t.size(); } void DoSomething(const T& x){ ... x.size(); } > void DoSomething(const uint8_t* p, size_t numBytes) This is awful you lose type info irreversibly. > template <typename T>
void DoSomething(std::span<T> data) You can do this but the above examples work just as well. > Or maybe something even more complicated, like this? template <typename T, std::size_t N>
void DoSomething(std::span<T, N> data) // Or this?
template <typename T, std::size_t N>
void DoSomething(std::span<const T, N> data) This is more explicit, not more complicated... > In this way, we still keep the clarity and simplicity of the function invocation:
> DoSomething(&data, sizeof(data)); Stripping types is not a good idea, especially because you'll run into object lifetime issues _REALLY QUICKLY_. You need to guarantee that the object is trivially copyable. |