Home > Blockchain >  Syntax for check if all variadic parameters are trivially copyable
Syntax for check if all variadic parameters are trivially copyable

Time:07-29

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");
  • Related