This is my first attempt at using QtConcurrent::blockingMappedReduced, and I can't get it to build in MSVC 2010 Express (with QT 4.7.1 source code).
I have created a small example that is similar to my actual code, and it has the same problem building:
// Here's the general outline:
// 1. create a list of random numbers
// 2. pass the list to blockingMappedReduced
// 3. the map function calculates the sine of the given random number
// 4. the reduce function finds the random number with the maximum sine value
// Here's the implementation:
#include "stdafx.h"
#include <qlist.h>
#include <qtconcurrentmap.h>
// My class for the map/reduce functions
class myClass
{
private:
// Nested class to hold the intermediate results from the map function
// I think I need this because the reduce function needs more from the map function than a single return value
class Temp
{
public:
// For example, let's pass these two member variables from the map function to the reduce function
int randomInput;
double resultingOutput;
// The Temp constructor
Temp::Temp(double randomInput, double resultingOutput)
{
this->randomInput = randomInput;
this->resultingOutput = resultingOutput;
}
};
public:
// For example, these myClass members will hold the final result from the reduce function
double maximumOutput;
double maximumInput;
// The myClass constructor
myClass::myClass()
{
this->maximumOutput = -1;
}
// The map function
const Temp mapFunction(const double& randomInput)
{
// For example, let's calculate the sine of the given random number
double resultingOutput = sin(randomInput);
// Construct the temporary structure to pass multiple values to the reduce function
const Temp temp(randomInput, resultingOutput);
return(temp);
}
// The reduce function
void reduceFunction(double& maxInput, const Temp& temp)
{
// For example, let's find the maximum computed sine value
if (temp.resultingOutput > this->maximumOutput)
{
this->maximumOutput = temp.resultingOutput;
this->maximumInput = temp.randomInput;
}
maxInput = this->maximumInput;
}
};
// Main function
void main(int argc, _TCHAR* argv[])
{
// Build a list of random numbers
QList<int> aList;
for (int count = 8; count > 0; --count)
{
aList.append(rand());
}
// Invoke the parallel map/reduce function
myClass myClassInstance;
double theAnswer = QtConcurrent::blockingMappedReduced(aList, &myClass::mapFunction, &myClass::reduceFunction);
}
The compiler complains about the last line, where blockingMappedReduced is invoked.
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2780: 'D QtConcurrent::blockingMappedReduced(Iterator,Iterator,T (__thiscall C::* )(void) const,U (__thiscall D::* )(V),QtConcurrent::ReduceOptions)' : expects 5 arguments - 3 provided
c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(659) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2780: 'C QtConcurrent::blockingMappedReduced(Iterator,Iterator,T (__cdecl *)(U),V (__thiscall C::* )(W),QtConcurrent::ReduceOptions)' : expects 5 arguments - 3 provided
c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(643) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2780: 'V QtConcurrent::blockingMappedReduced(Iterator,Iterator,T (__thiscall C::* )(void) const,U (__cdecl *)(V &,W),QtConcurrent::ReduceOptions)' : expects 5 arguments - 3 provided
c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(627) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2780: 'W QtConcurrent::blockingMappedReduced(Iterator,Iterator,T (__cdecl *)(U),V (__cdecl *)(W &,X),QtConcurrent::ReduceOptions)' : expects 5 arguments - 3 provided
c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(611) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2780: 'ResultType QtConcurrent::blockingMappedReduced(Iterator,Iterator,T (__thiscall C::* )(void) const,ReduceFunctor,QtConcurrent::ReduceOptions)' : expects 5 arguments - 3 provided
c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(595) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2780: 'ResultType QtConcurrent::blockingMappedReduced(Iterator,Iterator,T (__cdecl *)(U),ReduceFunctor,QtConcurrent::ReduceOptions)' : expects 5 arguments - 3 provided
c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(579) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2780: 'C QtConcurrent::blockingMappedReduced(Iterator,Iterator,MapFunctor,T (__thiscall C::* )(U),QtConcurrent::ReduceOptions)' : expects 5 arguments - 3 provided
c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(563) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2780: 'U QtConcurrent::blockingMappedReduced(Iterator,Iterator,MapFunctor,T (__cdecl *)(U &,V),QtConcurrent::ReduceOptions)' : expects 5 arguments - 3 provided
c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(547) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2780: 'ResultType QtConcurrent::blockingMappedReduced(Iterator,Iterator,MapFunctor,ReduceFunctor,QtConcurrent::ReduceOptions)' : expects 5 arguments - 3 provided
c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(536) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2784: 'D QtConcurrent::blockingMappedReduced(const Sequence &,T (__thiscall C::* )(void) const,U (__thiscall D::* )(V),QtConcurrent::ReduceOptions)' : could not deduce template argument for 'T (__thiscall C::* )(void) const' from 'const myClass::Temp (__thiscall myClass::* )(const double &)'
c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(522) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2784: 'C QtConcurrent::blockingMappedReduced(const Sequence &,T (__cdecl *)(U),V (__thiscall C::* )(W),QtConcurrent::ReduceOptions)' : could not deduce template argument for 'T (__cdecl *)(U)' from 'const myClass::Temp (__thiscall myClass::* )(const double &)'
c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(508) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2784: 'V QtConcurrent::blockingMappedReduced(const Sequence &,T (__thiscall C::* )(void) const,U (__cdecl *)(V &,W),QtConcurrent::ReduceOptions)' : could not deduce template argument for 'T (__thiscall C::* )(void) const' from 'const myClass::Temp (__thiscall myClass::* )(const double &)'
c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(494) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2784: 'W QtConcurrent::blockingMappedReduced(const Sequence &,T (__cdecl *)(U),V (__cdecl *)(W &,X),QtConcurrent::ReduceOptions)' : could not deduce template argument for 'T (__cdecl *)(U)' from 'const myClass::Temp (__thiscall myClass::* )(const double &)'
c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(480) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2784: 'ResultType QtConcurrent::blockingMappedReduced(const Sequence &,T (__thiscall C::* )(void) const,ReduceFunctor,QtConcurrent::ReduceOptions)' : could not deduce template argument for 'T (__thiscall C::* )(void) const' from 'const myClass::Temp (__thiscall myClass::* )(const double &)'
c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(466) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2784: 'ResultType QtConcurrent::blockingMappedReduced(const Sequence &,T (__cdecl *)(U),ReduceFunctor,QtConcurrent::ReduceOptions)' : could not deduce template argument for 'T (__cdecl *)(U)' from 'const myClass::Temp (__thiscall myClass::* )(const double &)'
c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(452) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2784: 'C QtConcurrent::blockingMappedReduced(const Sequence &,MapFunctor,T (__thiscall C::* )(U),QtConcurrent::ReduceOptions)' : could not deduce template argument for 'T (__thiscall C::* )(U)' from 'void (__thiscall myClass::* )(double &,const myClass::Temp &)'
c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(438) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2784: 'U QtConcurrent::blockingMappedReduced(const Sequence &,MapFunctor,T (__cdecl *)(U &,V),QtConcurrent::ReduceOptions)' : could not deduce template argument for 'T (__cdecl *)(U &,V)' from 'void (__thiscall myClass::* )(double &,const myClass::Temp &)'
c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(424) : see declaration of 'QtConcurrent::blockingMappedReduced'
c:\gwa\tmp\stackoverflow\stackoverflow\stackoverflow.cpp(77): error C2783: 'ResultType QtConcurrent::blockingMappedReduced(const Sequence &,MapFunctor,ReduceFunctor,QtConcurrent::ReduceOptions)' : could not deduce template argument for 'ResultType'
c:\gwa\third_party\qt\qt-4.7.1\src\corelib\concurrent\qtconcurrentmap.h(414) : see declaration of 'QtConcurrent::blockingMappedReduced'
From the online QT documentation (http://doc.qt.nokia.com/4.7-snapshot/qtconcurrentmap.html#blockingMappedReduced), here's the prototype:
T blockingMappedReduced ( const Sequence & sequence, MapFunction mapFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions = UnorderedReduce | SequentialReduce )
I'm afraid I don't have the expertise to debug this. Any help would be greatly appreciated. Again, since my C++ skill is not expert, the help would need to be explicit in order for me to understand it (i.e. actual code snippets, not something that presumes more knowledge than I have, like "your argument must be a constant reference").
Thanks in advance for your help.
Your code has a few general issues to patch up that aren't QtConcurrent related. Firstly, you shouldn't qualify the constructors, so instead of:
You should write simply:
Same for
myClass. Also, your function signature for main should always return anintalthough in C99 and C++ you can omit the return statement if you want to return 0. (I, however, always explicitly putreturn 0as a matter of personal preference.)What should main() return in C and C++?
As for your QtConcurrent issues, there are a couple. First your QList is of integers, and the documentation points out that the type in the sequence should match the first parameter of the map function (where you have a double). So the QList needs to change to double -or- your map function needs to take an int.
Another problem you have is the fact that you are trying to pass pointers to member functions into slots that expect just plain-ol functions:
Note that there is no mention of
myClassInstancebesides the declaration. In the general case...working around this is not as easy as changing the call to use&myClassInstance::mapFunction, &myClassInstance::reduceFunction. As you look around at C++ you will find there's no generally workable way to make objects that can fit in any slot a function call can, even if they're designed to appear to be callable like functions:Help with boost bind/functions
Luckily, QtConcurrent doesn't paint you into a corner on this. It anticipated the need for function objects:
http://doc.qt.io/archives/qt-4.7/qtconcurrentmap.html#using-function-objects
But rather than digging into how to make that work, we should consider why you would want these as member functions in the first place. The Map/Reduce model lets you define custom accumulator and result types, and that can get you what you want without that trouble. Here's a simpler version that hopefully will compile and get you closer:
Included some general C++ notes, hopefully helpful...
UPDATE: Another route they offer does use member functions, but it makes a couple of different assumptions from the style you were trying to write. Firstly, it assumes that your sequence input type is a class (
doubleis a "POD" or "plain-old-data" type and does not have method dispatch). Then the parameter is implicit.But note that if you wanted to use this technique it would stylize the code in a particular way. Here are the changes:
You can pick and choose...in this case it's probably better to do the reduceFunction as a member. But kind of ugly to be changing the input sequence type, and that's not the right place for parameters to the process--you want a function object.
(Also bear in mind that a writable state that the map function can get to undermines the parallelism of MapReduce. The map operations are supposed to really only generate output via their result so they stay independent...)