johnmastroberti
johnmastroberti

Reputation: 847

QtConcurrent::mapped return type issues

I want to use QtConcurrent::mapped to process a std::vector of data in parallel. Everything seems to work fine when I use a free function as the MapFunctor argument to QtConcurrent::mapped. However, when I use a lambda or a member pointer, the future returned is a QFuture<void>, not a QFuture of the result type. Below is a minimal reproducible example:

#include <QtConcurrent>

int free_func(int x) { return x + 3; }

struct S {
  int x;

  int func(S y) { return x + y.x; }
};

void example() {
  std::vector<int> v = {1, 2, 3};

  QFuture<int> f1 = QtConcurrent::mapped(v, free_func);
  QFuture<int> f2 = QtConcurrent::mapped(v, [](int x) { return x + 1; });

  std::vector<S> v2 = {S{1}, S{2}, S{3}};
  QFuture<int> f3 = QtConcurrent::mapped(v2, &S::func);
}

As far as I can tell from reading the Qt documentation, this should all be fine. However, I get compilation errors for f2 and f3 that read

.../test.cpp:15: error: conversion from ‘QFuture<void>’ to non-scalar type ‘QFuture<int>’ requested
.../test.cpp: In function ‘void example()’:
.../test.cpp:15:41: error: conversion from ‘QFuture<void>’ to non-scalar type ‘QFuture<int>’ requested
   15 |   QFuture<int> f2 = QtConcurrent::mapped(v, [](int x) { return x + 1; });
      |                     ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

and something similar for f3. Why should f2 and f3 QFuture<void> instead of QFuture<int>?

(I know I have to actually use the futures after creating them, my question is just about the types of the futures.)

Upvotes: 0

Views: 397

Answers (2)

rafix07
rafix07

Reputation: 20938

Version with S::func doesn't work because func has wrong signature.

If you have a collection C, mapped function iterates over all elements in this collection calling passed member function for each instance of C.

vector<S> C{S(1),S(2),..};

by

mapped(C,&S::func)

will be performed:

   C[0].func();
   C[1].func();
   ...

where above calls are performed by map-function whose signature is:

   RetType mapFunction(const S&)

member function is invoked for const object, so should be marked as const too.

struct S {
  int x;
  int func() const { return x + 1; } // + const and no arguments
};

void example() {
  std::vector<S> v2 {S{1}, S{2}, S{3}};
  QFuture<int> f3 = QtConcurrent::mapped(v2, &S::func);

Is fine.

Upvotes: 2

chehrlic
chehrlic

Reputation: 958

The automatic type deduction does not work with lambdas, you have to pass a proper std::function std::function<int(int)> f = [](int x) { return x + 1; }; QFuture<int> f2 = QtConcurrent::mapped(v, f);

f3 can't work since S::func() is no static function and therefore can't be used here.

Upvotes: 2

Related Questions