QtConcurrent::mappedReduced without mapped - c++

Consider the following code (Qt 6.0.3, C++17):
const QVector<int> arr = {1, 2, 3, 4, 5};
auto future = QtConcurrent::mappedReduced<int>(arr, [](auto item) {
return item;
}, [](int& result, auto item) {
result += item;
});
As you can see the first lambda expression passed to QtConcurrent::mappedReduced looks unnecessary. That's why I want to find something like QtConcurrent::reduced in Qt 6. Or how can I refactor this code to use only 1 lambda expression?

You can use std::accumulate.
The goal of QtConcurrent mappedReduce is the apply an operation on all the items of container in a concurrent fashion and once done do the reduction.
In your case there's nothing to be done but the sum of the items so there's no need for mappedReduce.
Update:
Based on your comments here is an example using a custom class with the operator+ overloaded using a QList as container.
class MyClass
{
public:
MyClass(int x=0, int y=0):
_x(x),
_y(y)
{}
int x() const { return _x; }
int y() const { return _y; }
public:
int _x;
int _y;
};
MyClass operator+(const MyClass& left, const MyClass &right)
{
MyClass m;
m._x = left._x + right._x;
m._y = left._y + right._y;
return m;
}
Here is a version with std::accumulate
#include <QVector>
#include <QtDebug>
#include <numeric>
int main(int argc, char **argv)
{
Q_UNUSED(argc);
Q_UNUSED(argv);
QVector<MyClass> myClassList = {MyClass(12, 42), MyClass(23, 53)};
MyClass result = std::accumulate(myClassList.constBegin(), myClassList.constEnd(), MyClass());
qDebug() << result.x() << result.y();
return 0;
}
Update 2:
Based on #IlBeldus suggestion, here is the version were you use std::accumulate with QtConcurrent::run
#include <QtDebug>
#include <QVector>
#include <QtConcurrent>
#include <numeric>
MyClass myAccumulate(const QVector<MyClass> &input)
{
return std::accumulate(input.constBegin(), input.constEnd(), MyClass());
}
int main(int argc, char **argv)
{
Q_UNUSED(argc);
Q_UNUSED(argv);
QVector<MyClass> myClassList = {MyClass(12, 42), MyClass(23, 53)};
QFuture<MyClass> future = QtConcurrent::run(myAccumulate, myClassList);
result = future.result();
qDebug() << result.x() << result.y();
return 0;
}

Related

Error when inserting vector of objects into set of vectors of objects

I would like to populate a set with a vector of tile objects, but I get an error.
#include <set>
#include <vector>
using namespace std;
struct tile
{
int value;
int suit;
};
tile makeTile(const int &a, const int &b)
{
tile t{a, b};
return t;
}
int main()
{
set<vector<tile>> s;
vector<tile> v;
v.push_back(makeTile(0, 0));
s.insert(v); // Error
return 0;
}
I don't get an error if I use integers rather than objects.
#include <set>
#include <vector>
using namespace std;
int main()
{
set<vector<int>> s;
vector<int> v;
v.push_back(0);
s.insert(v); // No error
return 0;
}
you can't make a set(actually ordered) of objects where logical operation is not possible.
But definitely you can make set by defining the logical operation by yourself. In programming sense, you can make set after doing some operator overloading.
Actually set is ordered set so you need to overload < operator for your struct.
Here is the code segment;
#include <iostream>
using namespace std;
struct tile{
int value;
int suit;
bool operator<(const tile& a);
};
tile makeTile(const int &a, const int &b)
{
tile t{a,b};
return t;
}
bool operator<(const tile& a, const tile& b){
return a.value <= b.value;
}
int main()
{
set<vector<tile> > s;
vector<tile> v;
v.push_back(makeTile(0,0));
v.push_back(makeTile(0,5));
v.push_back(makeTile(-1,5));
s.insert(v); // No Error here
}
if you want to check it then you can check it by following code:
for(auto &i:s){
for(auto &b:i){
cout << b.value << " " << b.suit << endl;
}
}
hope it will help.

How to add a class' function to the overload resoution list within the other function of the same class?

The question is within the code snippet:
#include <algorithm>
#include <utility>
#include <iostream>
struct A {
static int max(std::pair<int, int> const& pair) {
return std::max(pair.first, pair.second);
}
int use_max(std::pair<int, int> const & p, int const i) {
// 1) The following works fine:
// return std::max(i, max(p));
// 2) The following also works fine:
// using std::max;
// return max(i, this->max(p));
// 3) This does not compile, afaiu cause the A::max did
// not even got into the overload resolution list due to
// name look up rules.
using std::max;
return max(i, max(p));
// Question: What do I write here to add A::max into the
// overload resolution list, e.g., something like:
// using std::max;
// using A::max;
// return max(i, max(p));
}
};
int main() {
std::cout << A().use_max(std::make_pair(2, 3), 1);
}
using A::max; is not possible since A is a class and not a namespace.
And the answer to your query is simple:
return max(i, A::max(p));
I am not sure what else are you hoping to achieve here.
Update: Thought about it some more and you can modify code this way?
#include <algorithm>
#include <utility>
#include <iostream>
struct B {
static int max(int A, int B)
{
return std::max(A,B);
}
};
struct A:B{
static int max(std::pair<int, int> const& pair) {
return std::max(pair.first, pair.second);
}
using B::max;
int use_max(std::pair<int, int> const & p, int const i) {
return max(i, max(p));
}
};
int main() {
std::cout << A().use_max(std::make_pair(2, 3), 1);
}

Tbb library: error: no match for call to function when writing custom class function instead of lambda expression

I learning Thread Building Block with book "Pro TBB".
I want to rewrite to class function instead of using lambda expression as author wrote.
This is original source of the book, which I tested and it worked:
#include <iostream>
#include <tbb/tbb.h>
int main()
{
tbb::parallel_invoke(
[](){std::cout<<"Hello "<<std::endl;},
[](){std::cout<<"TBB! "<<std::endl;}
);
return 0;
}
But when I write as follow:
#include <iostream>
#include <tbb/tbb.h>
using std::cout;
using std::endl;
void print_function(const std::string &s)
{
cout<<s<<endl;
}
class printClass
{
private:
const std::string &myString;
public:
printClass(const std::string &s): myString{s} {};
void operator()(std::string s) const{
print_function(myString);
}
};
int main()
{
std::string s1 = "Hello", s2 = "TBB!";
tbb::parallel_invoke(
printClass(s1),
printClass(s2)
);
return 0;
}
It produced error:
In file included from /usr/local/include/tbb/tbb.h:61:0,
from figure_1_04_class.cpp:2:
/usr/local/include/tbb/parallel_invoke.h: In instantiation of ‘tbb::task* tbb::internal::function_invoker<function>::execute() [with function = printClass]’:
figure_1_04_class.cpp:30:1: required from here
/usr/local/include/tbb/parallel_invoke.h:47:24: error: no match for call to ‘(const printClass) ()’
my_function();
^
figure_1_04_class.cpp:17:10: note: candidate: void printClass::operator()(std::__cxx11::string) const
void operator()(std::string s) const{
^
figure_1_04_class.cpp:17:10: note: candidate expects 1 argument, 0 provided
I follow their example in chapter 2 in the book above.
This is their example and it worked too:
#include <vector>
#include <tbb/tbb.h>
#include <iostream>
using std::cout;
using std::endl;
void print_fucntion(int v)
{
cout<<"v: "<< v<<endl;
}
void sidebar_pfor_lambda(int N, const std::vector<int> &a)
{
tbb::parallel_for(0, N, 1, [&a](int i)
{
print_fucntion(a[i]);
});
}
int main()
{
std::vector<int> v = {4, 5, 6, 7, 8};
sidebar_pfor_lambda(5, v);
return 0;
}
#include <vector>
#include <tbb/tbb.h>
#include <iostream>
using std::cout;
using std::endl;
void print_fucntion(int v)
{
cout<<"v: "<< v<<endl;
}
class Body
{
private:
const std::vector<int> &myVector;
public:
Body(const std::vector<int> &v) : myVector{v} {};
void operator()(int i) const {
print_fucntion(myVector[i]);
}
};
void sidebar_pfor_function(int N, const std::vector<int> &a)
{
tbb::parallel_for(0, N, 1, Body(a));
}
int main()
{
std::vector<int> v = {4, 5, 6, 7, 8};
sidebar_pfor_function(5, v);
return 0;
}
What am I doing wrong and how to fix it?
tbb::parallel_invoke expects functional objects that can be invoked with zero arguments:
The expression parallel_invoke(f0,f1,...,fk) evaluates f0(), f1(), ..., fk() possibly in parallel.
Lambdas in your first example can be invoked in this way:
auto l = [](){ std::cout << "Hello" << std::endl; };
l(); // This is OK
But the functional object printClass expects one argument:
std::string s1 = "Hello";
auto l = printClass(s1);
l(); // Not OK!
The compiler complains:
candidate expects 1 argument, 0 provided
The solution is pretty simple – remove the unnecessary argument (what is it there for?):
class printClass {
// ...
void operator()(/* std::string s */) const {
print_function(myString);
}
};

How to make apply-visitor not discard const qualifier?

Is it possible to write const function with apply_visitor inside?
For example, this code compiles without errors:
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <boost/variant.hpp>
using namespace std;
typedef boost::variant<int,string> vTypeVariants;
struct vType_toN : boost::static_visitor<int>
{
int operator()(int& i) const {
return i;
}
int operator()(const string& str) const{
return str.length();
}
};
class vType{
public:
vType(const int& src) : data(src){}
vType(const std::string& src) : data(src){}
int getLength(){
return boost::apply_visitor(vType_toN(),data);
}
private:
vTypeVariants data;
};
int main(int argc, char ** argv)
{
vType x = string("2");
printf("L=%d",x.getLength());
return(0);
}
Unless you will add const to getLength():
int getLength() const{
return boost::apply_visitor(vType_toN(),data);
}
In such case an error with vast description (2 pages) appears complaining about problem with initializing first argument.
So, the question is: How to use apply_visitor inside const function?
Found out myself.
Forgot const before int in static_visitor class operator definition.
Maybe someone will find this useful as it was not easy to find this out (my original class is much bigger).

boost::phoenix error message while used as a functor

I am trying to learn boost::phoenix and trying to use it in std::transform like below.
class myClass
{
int i;
public:
getNumber();
setNumber(int j);
};
int main()
{
std::vector<myClass*> vect
std::vector<int> numVect
numVect.resize(vect.size());
using boost::phoenix::arg_names::arg1;
std::transform (vect.begin(), vect.end(), numVect.begin(), arg1->getNumber());
}
But, I am getting an error error: base operand of '->' has non-pointer type 'const boost::phoenix::actor<boost::phoenix::argument<0> >'
I am not really sure what does it mean. Any help would be great. Thanks
As you note above, the way to do this with Phoenix is with phoenix::bind or with ->* as you do above:
#include <vector>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/range/algorithm/transform.hpp>
class myClass
{
int i;
public:
int getNumber() { return i; }
void setNumber(int j) { i = j; }
};
int main()
{
std::vector<myClass*> vect;
std::vector<int> numVect;
using boost::phoenix::arg_names::arg1;
boost::transform(vect,
std::back_inserter(numVect),
(arg1->*&myClass::getNumber)());
}
Phoenix can be complicated, and bind expressions are some of the most convoluted and contrived of Phoenix's syntactic contortions, but in all honestly, this one doesn't seem that bad.
C++14's polymorphic lambdas will obviate much of Phoenix, by the way.
I'd use
std::transform (vect.begin(), vect.end(), numVect.begin(), phx::bind(&myClass::getNumber, arg1));
Or, if you wanted nicer syntax:
auto getNumber = phx::lambda [ phx::bind(&myClass::getNumber, arg1) ];
std::transform (vect.begin(), vect.end(), numVect.begin(), getNumber(arg1));
Demo:
#include <vector>
#include <algorithm>
#include <iostream>
#include <boost/phoenix/phoenix.hpp>
namespace phx = boost::phoenix;
struct myClass
{
int i;
int getNumber() const { return i; }
void setNumber(int j) { i = j; }
};
using namespace boost::phoenix::arg_names;
static const auto getNumber = phx::lambda [ phx::bind(&myClass::getNumber, arg1) ];
int main()
{
const std::vector<myClass*> vect { new myClass{1}, new myClass{2}, new myClass{42} };
std::vector<int> numVect(vect.size());
// puritan/standard version:
std::transform (vect.begin(), vect.end(), numVect.begin(), std::mem_fn(&myClass::getNumber));
// just bind:
std::transform (vect.begin(), vect.end(), numVect.begin(), phx::bind(&myClass::getNumber, arg1));
// using more natural syntax
std::transform (vect.begin(), vect.end(), numVect.begin(), getNumber(arg1));
for(auto i : numVect)
std::cout << i << " ";
}