Search code examples
c++variadic-templatesvariadic

Variadics template without tuple


I'm working on a project quite particular since I can't use all C++11 features. In particular, I have variadics template but no tuple. What I'm struggling to do is to create a templated class which can store meta-data, ie a set of data. I don't know in advance what type is used, and how many of them there will be. Basically, that's what I want to do

#include<tuple>
template<typename... Data>
class Base{
 private:
std::tuple<Data...> mydata;

public:
Base{Data... data):
    mydata(data...){}

void set_data(Data... data){
    mydata = std::tie(data...)
}

This example is working...but relied on tuple. I know that I can do something similar without tuple, using ArgumentPack. However, I'm not familiar with that.

So far, I thought about using struct to store my data, since it's the only other way I know to store different types. So I should look like this :

template<typename typename<...> class ArgumentPack, typename... Data>
class Base{
 private:
struct mydata{
//Something here
};

public: 
Base(Data... data){
    //assign data into mydata struct
}

void set_data(Data... data){
    //???
}

mydata get_data(){
    //???
}

Solution

  • Theoretically you could build a little bit more complicated structure on the Vittorio's approach by giving additional wrapper. This one would actually allow the multiple data of the same type as well as primitive types. The sketch of the approach (using c++14 to do index_sequence stuff, but can be reimplemented in c++11 without std as well):

    #include <utility>
    #include <iostream>
    
    template <class... Ts>
    struct Pack {};
    
    template <std::size_t, class T>
    struct Wrapper {
        T t;
        Wrapper(T t): t(t) { }
    };
    
    template <class... Ts>
    struct Foo: Foo<Pack<Ts...>, std::make_index_sequence<sizeof...(Ts)>> { 
        using  Foo<Pack<Ts...>, std::make_index_sequence<sizeof...(Ts)>>::Foo;
    };
    
    template <class... Ts, std::size_t... Is>
    struct Foo<Pack<Ts...>, std::index_sequence<Is...>>: Wrapper<Is, Ts>... {
        Foo(Ts... ts):Wrapper<Is, Ts>(ts)... { }
        void set_data(Ts... ts) {
            this->~Foo();
            new (this) Foo (ts...);
        }
        template <std::size_t I, class T>
        static T& get_data_impl(Wrapper<I, T>* th) {
            return th->t;
        }
        template <std::size_t I>
        auto get_data() -> decltype(get_data_impl<I>(this)) {
            return get_data_impl<I>(this);
        }
    };
    
    int main() {
        Foo<int, float, int> foo(1, 2.0f, 3);
        foo.set_data(3, 2, 1);
        std::cout << foo.get_data<2>() << std::endl;
    }
    

    [live demo]