0

I don't know if it's possible to achieve what I'm trying but maybe someone can guide me in the right direction. Sidenote: this is on an embedded system.

I have an SPI communication that returns a std::vector<int> representing a set of registers. This is done in a separate thread so asynch. To handle this, I create an object on every read call containing a std::promise<std::vector<int>> (and some other information) and directly return the future of it, so the caller can wait for the result.

Once the SPI transfer is complete, I set the value of the promise accordingly. So far so good.

Now what I'd like to do is to not always return a future of type std::vector<int> but do some preprocessing on the vector and return either int or double or even a struct. I thought I can achieve that by handing an anonymous function to the read function and store a reference in the object. This function would then be called before the promise is assigned.

The problem I now have is that the return type of this function directly affects the return type of my promise and the object storing them is not always the same anymore. So I thought I just template it

template <class ret_type>
class obj{
    public:
    std::promise<ret_type> prms;
    ret_type (*map_function)(std::vector<int>);
    ...
};

But now I have to problem that my vector containing these objects (the SPI queue) that was of type std::vector<obj> cannot hold objects of different types.

Is there a proper way to solve that?

edit: I'd use the vector in a way like

for(auto &element : vector){
    std::vector<int> answer_from_spi = spi_read();
    element.prms.set_value(element.map_function(answer_from_spi));
}
po.pe
  • 1,047
  • 1
  • 12
  • 27
  • Maybe you just need to use `std::variant`? – CrafterKolyan Aug 22 '18 at 07:14
  • If there's a solution without std::variant that would be great because otherwise I'd have to specify all possible return types which can be quite a few. Maybe I'm wrong but how should a vector of type `std::vector` look like if `ret_type` is a type specifier of my class? – po.pe Aug 22 '18 at 07:24
  • So suppose you could store objects of different types in your hypothetical `std::vector` (in reality `obj` is not a type, so such vector cannot exist, but let's forget about it for a second). How would you use this vector? Please show (pseudo)code. – n. m. could be an AI Aug 22 '18 at 07:54
  • Why should `std::vector` not be valid if I define a class named `obj`? Added pseudo code to question – po.pe Aug 22 '18 at 08:12
  • If you do not need a class private/public data of templated type , you have a templated function inside a non-templated class ... or you can create the templated data locally inside the templated function – AdityaG Aug 22 '18 at 15:00
  • 1
    You have defined `obj` as a template, hence `obj` is not a type and `vector` does not exist. If you define `obj` as a type instead, then what type is `obj::prms`? – n. m. could be an AI Aug 22 '18 at 17:02

2 Answers2

1

Note: As I don't have enough reputation to comment, I am writing an answer.

If you can use C++17, then maybe you can use std::any. https://en.cppreference.com/w/cpp/utility/any

Before C++17, you can create a polymorphic classes (Define a base class, derived classes for different types you want to return and store) and store the pointers to them in the vector. Something like this:

vector<Base*> vec; vec.push_back(derived1); vec.push_back(derived2);

Please see the below answer:

Vector that can have 3 different data types C++

cpp_enthusiast
  • 1,239
  • 10
  • 28
1

The bog-standard solution consists of moving your entire type-varying part into a virtual function. Store (smart) pointers to the base class in your vector, and have the virtual function implemented in derived classes.

class obj {
  public:
    virtual void set_promise () = 0;
};

template <class ret_type>
class obj_impl : public obj {
    std::promise<ret_type> prms;
    ret_type (*map_function)(const std::vector&<int>);
    void set_promise () override {
        std::vector<int> answer_from_spi = spi_read();
        prms.set_value(map_function(answer_from_spi));
    }
};

std::vector<std::unique_ptr<obj>> objects;
for(auto &element : objects)
    element->set_promise();
n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • How would I set `map_function`? It's telling me that `obj` doesn't have such a member... – po.pe Aug 23 '18 at 09:12
  • @Humpawumpa indeed, obj doesn't, and cannot, because you don't know the type. obj_impl is responsible for this function. Why are you trying to use it in obj? The whole idea is to hide it from obj. – n. m. could be an AI Aug 23 '18 at 09:16
  • Presumably you set map_function when constructing your specific obj_impl. At that point ret_type is known so you can do that. It could be a constructor argument. – n. m. could be an AI Aug 23 '18 at 09:19
  • I'm not explicitly trying to use it in obj... I just do `auto object = std::make_unique>()` and then `object->map_function = [](){}` but it seems like it doesn't access the derived class but the base class instead. – po.pe Aug 23 '18 at 09:19
  • This should work (if you make map_function public). Are you sure you are using `object` and not say `object_vector[i]` or something? You can ask a separate question about it, with a [mcve]. – n. m. could be an AI Aug 23 '18 at 09:22
  • Okay I'll do that – po.pe Aug 23 '18 at 09:25