2

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(){
    //???
}
Ezor
  • 135
  • 2
  • 18
  • 1
    What you're asking is "how do I reimplement tuple"? right? – Richard Hodges Oct 26 '17 at 09:21
  • more or less. It will be better if I could store these data in a structure whithout reiplementing tuple – Ezor Oct 26 '17 at 09:23
  • The above code does nothing with the stored data, except assign over it and store it. In order to answer this question, people are going to need (A) every restriftion on the stored data you know about, and (B) every operation you want to perform on them inside the template. The answer will look like "reimplement (part of) tuple" probably, because tuple is a structure that holds a pack of types. That is what it is, its essential nature. Now, for example, do you mind a pile of spurious allocation? Do you have `any`? There is an inefficient hack. – Yakk - Adam Nevraumont Oct 26 '17 at 09:25
  • i edited my post. But basically, I just need simple function as `set_data(data)` and `get_data()`. `any` is part of C++17 right? In that case I can't use it either. – Ezor Oct 26 '17 at 09:31

2 Answers2

4

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]

W.F.
  • 13,888
  • 2
  • 34
  • 81
  • seems pretty complicated, but I'll have a look. However, I have access to a limited amount of C++11 features. And nothing with C++14. – Ezor Oct 26 '17 at 10:04
  • @Ezor as I said I think only `index_sequence` is c++14 here but it can be relatively simply implemented also in c++11. As such I think nothing from `std` namespace would actually be needed here... – W.F. Oct 26 '17 at 10:07
  • 1
    little improvement suggestion: if you create a type traits that return the nth type of a list, you can call `get_data()` using only the index template type (I mean `foo.get_data<2>()`); something like `template nTh_t & get_data() { return this->Wrapper>::t; }` – max66 Oct 26 '17 at 11:33
  • @max66 good point, but it would make the code a little less understandable. I added this version to make it as verbose as possible for OP, while still having required functionality... – W.F. Oct 26 '17 at 14:49
  • it's was just an idea; anyway, it's a really good answer (IMHO) as it is. – max66 Oct 26 '17 at 15:54
  • @max66 I've addressed the problem and it seems wasn't so demanding nor code consuming :) I mean - I thought it would get more complicated when restricting to c++11... – W.F. Oct 26 '17 at 18:55
  • Do you mean that `T` is *deduced* passing `this` because `*this` is also (inherit from) a `Wrapper` ? Wow! I never thought it. Yes: simple and elegant. – max66 Oct 26 '17 at 19:22
  • @max66 yes I think this is possible because there is no ambiguity in deduction - if the `Wrapper` would inherit from other `Wrapper` specialization I think it would break the code... – W.F. Oct 26 '17 at 19:25
  • Considering this as a basic example, I would prefer a version without the call to (de)constructors in `set_data`. – Julius Oct 28 '17 at 15:43
  • @julius this is also possible but would reqired additional stretchin' using `index_sequence` – W.F. Oct 28 '17 at 16:30
3

If your types are all different and not primitive, you might get away with inheritance:

template <typename... Data>
class Base : Data...
{
};

Otherwise, you should use a library providing tuple or implement your own. E.g.boost::tuple.

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416