There may be ways of replacing the standard library implementation of memcpy
with something that saves data about any copying done (see e.g. How to replace C standard library function ? ), but in general it would be easiest to pass an additinal template parameter in that contains implementations for the copying:
struct default_copier
{
void memcpy(void* dest, void const* src, size_t size) const noexcept
{
std::memcpy(dest, src, size);
}
};
template<class T, class Copier = default_copier>
class my_vector
{
[[no_unique_address]] Copier m_copier;
T m_values [10]{};
public:
my_vector()
{
}
void fill_first(T const* values, size_t size)
{
if constexpr (std::is_trivially_copyable_v<T>)
{
m_copier.memcpy(m_values, values, sizeof(T) * size);
}
else
{
std::copy_n(values, size, m_values);
}
}
Copier& copier()
{
return m_copier;
}
};
struct test_copier
{
size_t m_memcpyUseCount{ 0 };
void memcpy(void* dest, void const* src, size_t size)
{
std::memcpy(dest, src, size);
++m_memcpyUseCount;
}
};
int main() {
{
my_vector<int, test_copier> vectorOfTriviallyCopyable;
int buffer[2]{};
vectorOfTriviallyCopyable.fill_first(buffer, std::size(buffer));
assert(vectorOfTriviallyCopyable.copier().m_memcpyUseCount == 1);
}
{
my_vector<std::string, test_copier> vectorOfNonTriviallyCopyable;
std::string buffer[2]{};
vectorOfNonTriviallyCopyable.fill_first(buffer, std::size(buffer));
assert(vectorOfNonTriviallyCopyable.copier().m_memcpyUseCount == 0);
}
return 0;
}