Aggiornamento:
HO scelto i template in vulkan perch� ha un ampia fase di configurazione a design time e praticamente la parte dinamica � piccolissima. eccetera...
Qualcosa si può fare, ma dipende da quante singole strutture parliamo.
Qui ho prodotto un test case, con tre strutture aventi campi diversi, dimensioni dei campi diversi ma tutti di tipo float. la funzione apivulkan() dovrebbe simulare il comportamento dell'API che vuoi usare (che spero prima o poi che tu la dica, in modo che possa leggerne la documentazione).
Da quello che ho visto ogni funzione che accetta un const void*, accetta anche un parametro di tipo VKStructureType (o qualcosa del genere) che immagino serva all'API a capire cosa le sta arrivando.
Continua a non esserci il CManager e onestamente non so come infilarcelo.
Qui sia a livello template extreme per cui dovresti cercare variadic template su google per maggiori info.
Spero sia quello che volevi fare o perlomeno che ci assomigli un po', in ogni caso buon divertimento.
codice:
#include "stdafx.h"
#include <string>
#include <iostream>
#include <tuple>
#include <vector>
#include <algorithm>

using namespace std;


struct Type1 {
    float a[3];
};

struct Type2 {
    float a[3];
    float b[2];
};

struct Type3 {
    float a[3];
    float b[2];
    float c[4];
};


template <typename T>
struct wrapper {
    T data;
    void set_data(const T& d) { 
        data = d; 
    }
    T get_data() { return data; }
};


template <std::size_t> struct Splat;

template <> struct Splat<1> {
    static const int t = 0;
    Type1 t1;
    template <typename C>
    Type1* to_bytes(C& c) {
        // azzero Type1
        memset(&t1,0,sizeof(Type1));
        vector<float> tmp = get<0>(c).get_data();
        // aspetto 3 valori
        size_t maxcpy = std::min<size_t>(3,tmp.size());
        copy_n(tmp.begin(),maxcpy,t1.a);
        return &t1;
    }
};

template <> struct Splat<2> {
    static const int t = 1;
    
    Type2 t2;
    template <typename C>
    Type2* to_bytes(C& c) {
        memset(&t2, 0, sizeof(Type2));
        vector<float> tmp = get<0>(c).get_data();
        // aspetto 3 valori
        size_t maxcpy = std::min<size_t>(3, tmp.size());
        copy_n(tmp.begin(), maxcpy, t2.a);

        vector<float> tmp1 = get<1>(c).get_data();
        // aspetto 2 valori
        maxcpy = std::min<size_t>(2, tmp1.size());
        copy_n(tmp1.begin(), maxcpy, t2.b);
        return &t2;
    }
};

template <> struct Splat<3> {
    static const int t = 2;
    Type3 t3;
    template <typename C>
    Type3* to_bytes(C& c) {
        memset(&t3, 0, sizeof(Type3));
        vector<float> tmp = get<0>(c).get_data();
        // aspetto 3 valori
        size_t maxcpy = std::min<size_t>(3, tmp.size());
        copy_n(tmp.begin(), maxcpy, t3.a);

        vector<float> tmp1 = get<1>(c).get_data();
        // aspetto 2 valori
        maxcpy = std::min<size_t>(2, tmp1.size());
        copy_n(tmp1.begin(), maxcpy, t3.b);

        vector<float> tmp2 = get<2>(c).get_data();
        // aspetto 4 valori
        maxcpy = std::min<size_t>(4, tmp2.size());
        copy_n(tmp2.begin(), maxcpy, t3.c);

        return &t3;
    }
};


template <typename... T> struct Vertex;

template <typename First, typename... Types>
struct Vertex<First,Types...> : Vertex <Types...> {
    typedef std::tuple<wrapper<First>,wrapper<Types>...> Tupla;
    static const size_t ID = std::tuple_size<Tupla>::value;
    Tupla tup;
    Splat<ID> splat;
    const void* test() { 
        return splat.to_bytes(tup);
    } 
};

template <typename First>
struct Vertex<First> {
    typedef std::tuple<wrapper<First>> Tupla;
    static const size_t ID = std::tuple_size<Tupla>::value;
    Tupla tup;
    Splat<ID> splat;
    const void* test() { 
        return splat.to_bytes(tup);
    }
};


void apivulkan(size_t type, const void* data) {
    if (type == 1) {
        const Type1* t1 = static_cast<const Type1*>(data);
        for (auto n : t1->a ) {
            cout << n << " ";
        }
        cout << endl;
    }

    if(type == 2) {
        const Type2* t2 = static_cast<const Type2*>(data);
        for(auto n : t2->a) {
            cout << n << " ";
        }
        cout << endl;
            
        for(auto n : t2->b) {
            cout << n << " ";
        }
        cout << endl;

    }

    if(type == 3) {
        const Type3* t3 = static_cast<const Type3*>(data);
        for(auto n : t3->a) {
            cout << n << " ";
        }
        cout << endl;

        for(auto n : t3->b) {
            cout << n << " ";
        }
        cout << endl;

        for(auto n : t3->c) {
            cout << n << " ";
        }
        cout << endl;
    }
}


int main() {

    Vertex<vector<float>> d;
    Vertex<vector<float>, vector<float>> d1;
    Vertex<vector<float>, vector<float>, vector<float>> d2;

    std::vector<float> v0{1.1f,2.1f,3.1f};
    get<0>(d.tup).set_data(v0);

    std::vector<float> v1a{ 4.1f,5.1f,6.1f };
    std::vector<float> v1b{ 7.1f,8.1f,9.1f };

    get<0>(d1.tup).set_data(v1a);
    get<1>(d1.tup).set_data(v1b);

    std::vector<float> v2a{ 10.1f,20.1f,30.1f };
    std::vector<float> v2b{ 40.1f,50.1f,60.1f };
    std::vector<float> v2c{ 70.1f,80.1f,90.1f,100.1f,200.1f };

    get<0>(d2.tup).set_data(v2a);
    get<1>(d2.tup).set_data(v2b);
    get<2>(d2.tup).set_data(v2c);

    apivulkan(d.ID, d.test());
    apivulkan(d1.ID, d1.test());
    apivulkan(d2.ID, d2.test());


}