Yesterday I answered this question.
One user commented that it will work only for trivally copyable data. That is clear, but not enforced. I wanted to add a static_assert
, but I use the wrong syntax. Here I need help.
To explain a little bit more. The functions can take containers that have a size()
and data()
member function, like for example a std::vector
and then copies the underlying data for all containers.
It cries for C 20 concepts. But I would like to see at first a C 17 solution.
The problem is in line
static_assert(std::conjunction_v<std::is_trivially_copyable_v<std::remove_pointer<decltype(std::declval<std::remove_cvref_t<args>().data())>::type>...>, "Not trivially copyable");
Instead of std::conjunction
a fold expression could be used as well.
What is the correct syntax?
Code:
#include <iostream>
#include <vector>
#include <array>
#include <numeric>
#include <cstddef>
#include <memory>
#include <algorithm>
#include <utility>
#include <type_traits>
template<typename...Args>
std::pair<void*, size_t> copyData(Args...args) {
//static_assert(std::conjunction_v<std::is_trivially_copyable_v<std::remove_pointer<decltype(std::declval<std::remove_cvref_t<args>().data())>::type>...>, "Not trivially copyable");
size_t overallSize = (0 ... (args.size() * sizeof(std::remove_cvref_t<decltype(args)>::value_type)));
std::byte* destination = new std::byte[overallSize];
std::byte* destinationAddress = destination;
((destinationAddress = std::copy((std::byte*)args.data(), (std::byte*)args.data() (args.size() * sizeof(std::remove_cvref_t<decltype(args)>::value_type)),
destinationAddress)), ...);
return { destination, overallSize };
}
int main() {
// Some demo data with different data types
std::vector <unsigned char> uc{ 0,1,2,3,4 };
std::array <short, 3> ss{ 5,6,7 };
std::vector <unsigned int> ui{ 8,9,10,11,12,13,14,15 };
std::array <long, 2> sl{ 16,17 };
std::vector <unsigned long long> ull{ 18,19,20,21,22,23 };
// Call function with any number of arguments
const auto& [pointer, size] = copyData(uc, ss, ui, sl, ull);
// Some debug output
for (size_t i{}; i < size; i)
std::cout << ((int)((std::byte*)(pointer))[i]) << ' ';
delete[] pointer;
}
Bonus would be to enforce that the parameter types have a size()
and data()
function and a value_type
But not that important, because, if they have not, then the compilation will fail anyway. Which is OK.
CodePudding user response:
The correct syntax would be
static_assert(std::conjunction_v<
std::is_trivially_copyable<
std::remove_pointer_t<
decltype(std::declval<Args&>().data())>>...>,
"Not trivially copyable");
However, there is no need to use decltype(std::declval<Args&>().data())
to get the return type of the data()
, since you are already inside the function, a simple decltype(args.data())
should be enough.
static_assert((
std::is_trivially_copyable_v<
std::remove_pointer_t<decltype(args.data())>> && ...),
"Not trivially copyable");