0

Consider the following function (myfct). When this function returns, data points to either uint16_t, float_t or double_t.

In main(), this function is called in a for loop. I want for each iteration to save "data" in a std::vector with the type it points to. How can I do that? Thanks in advance.

PS: the container must not necessarily be a vector, it can be anything else, I just want to save "data" without loosing the pointer type information.

void myfct(void*&data, int id) {
if(id==1) {
  uint16_t* ptr = ...;  
  data = ptr;
}
else if(id==2) {
  float_t* ptr = ...;  
  data = ptr;
}
else if(id==3) {
  double_t* ptr = ...;  
  data = ptr;
}
}

int main() 
{
    void* dataPtr = nullptr;
    vector<?> myVec; //how should I template my vector? which typename?
    for(int i = 0, i<5, i++) 
    {
        myfct(dataPtr , i);  //note that dataPtr is passed by reference
        myVec.push_back(dataPtr ); //here dataPtr point to either uint16_t, 
        //float_t or double_t. I want to save it with the type it point to.
    }
}
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Gaetan
  • 577
  • 2
  • 7
  • 20
  • 5
    What you want is `std::variant` or `std::any`. – NathanOliver Aug 02 '18 at 15:50
  • 4
    Whenever you are using a `void *` in C++ you are *very likely* doing it wrong. – Jesper Juhl Aug 02 '18 at 15:51
  • A `std::vector` can only hold data of *one* type. – Jesper Juhl Aug 02 '18 at 15:52
  • @JesperJuhl the container muss not be a vector, it can be anything else, I just want to save "data" without loosing the pointer type information. – Gaetan Aug 02 '18 at 15:55
  • @NathanOliver I'm unfortunately limited to c++11 – Gaetan Aug 02 '18 at 15:57
  • 2
    @Gaetan The "one type per container" bit goes for *all* the standard containers, not just `vector`. If you want multiple types, use multiple containers (or containers of `variant` or `any` as Nathan suggested). – Jesper Juhl Aug 02 '18 at 15:58
  • 1
    *I want to save it with the type it point to.* You probably want 3 vectors, one for each type. – super Aug 02 '18 at 15:59
  • @Gaetan Boost has C++11 compatible versions. – NathanOliver Aug 02 '18 at 16:00
  • if you already have the data stored somewhere and just need to store to pointers, you can [store the type of the variable in the pointer](https://stackoverflow.com/q/16198700/995714). Otherwise if you want to get data, use `std::variant` as Nathan said above – phuclv Aug 02 '18 at 16:14
  • @phuclv std::variant is a c++17 feature. I'm trying to use boost::variant. will let you guys know if it worked. Thanks for the replies. Some others idea maybe? – Gaetan Aug 02 '18 at 16:26
  • @Gaetan you might want to look at using a linked list instead of a vector – Chad K Aug 02 '18 at 18:05

2 Answers2

1

If you don't have access to std::variant, the way to do it would be the following:

class custom_type {
    int id;
    union data_holder
    {
        uint16_t i;
        float_t f;
        double_t d;
    } data;
}

Now, you can have a vector<custom_type>, and if you want to work with a data point, you can do

custom_type c = myvec.back();
if( c.id == 1 ) {
    uint16_t val = c.data.i;
    // Process val in a uint way
} else if( c.id == 2 ) {
    float_t val = c.data.f;
    // Process val in a float way
} ...

You can learn more about unions here. Now, in order to make your code handle the data types easily (So you don't have to write the similar "process val in an X way" over and over again), you can use templates. For example,

template <typename T>
T calculate(T val) {
    // Do stuff with val
    return computed_val;
}

And now,

custom_type c = myvec.back();
if( c.id == 1 ) {
    uint16_t val = calculate<uint16_t>(c.data.i);
    cout << val;
} else if( c.id == 2 ) {
    float_t val = calculate<float_t>(c.data.f);
    cout << val;
} ...
Nicholas Pipitone
  • 4,002
  • 4
  • 24
  • 39
  • `std::variant` is just a wrapper around a union anyway. If you _need_ it to be a pointer as shown in your question, then you can have the union encapsulate pointers instead of the types themselves. I don't think that's the right way to go about it though, you should just have a pointer to `custom_type` instead. – Nicholas Pipitone Aug 02 '18 at 18:03
0

What you want is polymorphism, e.g., a base class (can be an interface/abc) and then derived classes, which implement some typeof functor. I can give an example if you wish to, but I think it would be a lot more valuable for you to learn how to do it yourself. Another way is to use boost::variant or boost::any.

Ælex
  • 14,432
  • 20
  • 88
  • 129