Jon Chesterfield
Jon Chesterfield

Reputation: 2341

Inverting type erasure, i.e. get types back afterwards

I have a fairly generic work queue. It takes some number of std::function<void(void)> and executes them on N worker threads. Closures + type erasure working well.

Now however, I would like the functions to "return" some state, and I would prefer the queue know nothing about what the types might be. To that end, I am considering using a queue of

std::function <std::function<void(void)>(void)>

Which, if I can keep the syntax straight, is a function taking void and returning a function taking void and returning void. The idea being to add a second work queue to return the result of the task execution.

This doesn't strictly solve the problem though - I can then call the returned value, but this doesn't obviously allow me to retrieve the state.

I could return boost::any, which doesn't appear to tell me what the contained type is, or boost::variant which means providing the task library with a list of all possible return types. Neither seem ideal.

What I would like to do is encode the information required to interpret the result of the function call within the functor, but I do not see a clean way to achieve this. Bundling an execute() and an extract() method into a single void(void) functor is beyond my cunning.

An alternative workaround is a heterogenous work queue, but such a thing is also quite a pain to write in C++. I feel optimistic that there is an idiomatic solution for getting at the unknown type that results from executing type erased code, but guessing the search keywords has not gone well for me. Guidance would be appreciated.

edit: An outline of the intended workflow for the application code, as distinct from the work queue / thread pool layer

  1. Construct one or more tasks to execute asynchronously
  2. Package the tasks as std::function</*consistent type*/>
  3. Push onto queue provided by a library
  4. Do some other things for a while
  5. Retrieve an opaque type of some sort from the queue
  6. Pass this opaque type to a function that works out what it actually is
  7. All is well from here

edit: As suggested in the comments, type erasure goes both ways. Let the generic functor be:

struct functor 
{
  typedef std::function<void(void)> functype;
  functype async;
  functype result;
};

Then use an instance of queue<functor> for both send and receive. Async gets run on a remote thread. When an instance of functor comes back we have no idea what it represents, but the result() member does and can perform whatever next step is considered reasonable. This will probably suffice.

Upvotes: 1

Views: 171

Answers (1)

Mark B
Mark B

Reputation: 96241

(Copying from my comment):

Instead of having step 6 know the precise concrete type, what about solving your problem by using either dynamic or static polymorphism instead?

Upvotes: 1

Related Questions