Converting from `std::array>` to `void*` I'm doing some work with Vulkan, in this I need to pass a set of values of various types.
Currently I'm using std::array&lt;std::variant&lt;&gt;&gt; in my interface, but I must pass Vulkan a void*.
To convert to the void* I use this function:
template &lt;uint32_t Size&gt;
void* voidArray(std::array&lt;std::variant&lt;uint32_t,float&gt;,Size&gt;&amp; array, uint32_t size) {
    char* bytes = new char[size];
    uint32_t byteCounter = 0;
    for(uint32_t i=0;i&lt;array.size();++i) {
        if(float* flt = std::get_if&lt;float&gt;(&amp;array[i])) {
            *reinterpret_cast&lt;float*&gt;(bytes+byteCounter) = *flt;
            byteCounter += sizeof(float);
        }
        else if(uint32_t* uin = std::get_if&lt;uint32_t&gt;(&amp;array[i])) {
            *reinterpret_cast&lt;uint32_t*&gt;(bytes+byteCounter) = *uin;
            byteCounter += sizeof(uint32_t);
        }
    }
    void* data = static_cast&lt;void*&gt;(bytes);
    return data;
}

I get the size variable earlier within a larger function (names are a little more context specific):
// std::array&lt;std::variant&lt;uint32_t,float&gt;,NumPushConstants&gt;&amp; pushConstants
std::optional&lt;uint32_t&gt; pushConstantSize = std::nullopt; // later used for `size`
auto size_fn = [](auto variant) -&gt; uint32_t {
    using T = std::decay_t&lt;decltype(variant)&gt;;
    if constexpr (std::is_same_v&lt;uint32_t, T&gt;) { return sizeof(uint32_t); }
    if constexpr (std::is_same_v&lt;float, T&gt;) { return sizeof(float);}
};
pushConstantSize = std::accumulate(pushConstants.begin(),pushConstants.end(),0,
    [size_fn](uint32_t acc, auto variant) { return std::move(acc) + std::visit(size_fn,variant); }
);

Both of these implementations, most prominently the first rouse my suspicion of being bad.
Are they bad? Is there a better way? Am I missing something?
It's hard to provide overall feedback, since you don't want to provide any details. There's probably a much simpler way to structure all of this.
But some things about the specific code:

don't do manual memory management:
char* bytes = new char[size];

I hope this gets delete[]d somewhere. We should use a std::vector instead, and get a pointer from vector.data() when we actually need to.

use std::byte in C++17:
char* bytes = new char[size];

If we have it, we should use std::byte instead of char (since we're dealing with object representations in memory).

use memcpy, not reinterpret_cast; simplify:
    if(float* flt = std::get_if&lt;float&gt;(&amp;array[i])) {
        *reinterpret_cast&lt;float*&gt;(bytes+byteCounter) = *flt;
        byteCounter += sizeof(float);
    }
    else if(uint32_t* uin = std::get_if&lt;uint32_t&gt;(&amp;array[i])) {
        *reinterpret_cast&lt;uint32_t*&gt;(bytes+byteCounter) = *uin;
        byteCounter += sizeof(uint32_t);
    }

Due to &quot;strict aliasing rules&quot; I don't think this is technically correct (even if it apparently works). Our char array doesn't have floats in it, so we shouldn't pretend that it does and copy in a float. We should instead use std::memcpy to copy the underlying representation of the float into the array.
Note also that we're doing the exact same thing for both types, so we could probably do something like:
std::apply([&amp;] (auto const&amp; var) {
    using T = std::decay_t&lt;decltype(var)&gt;;
    std::memcpy(bytes + byteCounter, static_cast&lt;void const*&gt;(&amp;var), sizeof(T));
    byteCounter += sizeof(T);
}, array[i]);


same again (again):
The same thing is true of the second code snippet:
std::optional&lt;uint32_t&gt; pushConstantSize = std::nullopt; // later used for `size`
auto size_fn = [](auto variant) -&gt; uint32_t {
    using T = std::decay_t&lt;decltype(variant)&gt;;
    if constexpr (std::is_same_v&lt;uint32_t, T&gt;) { return sizeof(uint32_t); }
    if constexpr (std::is_same_v&lt;float, T&gt;) { return sizeof(float);}
};
pushConstantSize = std::accumulate(pushConstants.begin(),pushConstants.end(),0,
    [size_fn](uint32_t acc, auto variant) { return std::move(acc) + std::visit(size_fn,variant); }
);

We don't need the if statements:
auto size_fn = [] (auto const&amp; var) {
    using T = std::decay_t&lt;decltype(var)&gt;;
    return sizeof(T);
};
std::size_t size = std::accumulate(pushConstants.begin(), pushConstants.end(), std::size_t{ 0 },
    [=](std::size_t acc, auto var) { return acc + std::visit(size_fn, var); }
);

std::move won't help with a trivially copyable type, and we should be using std::size_t for the size.
The optional also seems redundant; we always have a size, even if the array is empty.
This snippet should be made a whole complete function by itself.