这是我第一次尝试使用QtConcurrent::blockingMappedReduced,我无法在MSVC2010Express(带有Qt4.7.1源代码)中构建它。
我已经创建了一个与我的实际代码类似的小示例,并且它具有相同的问题:
// 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);
}编译器会报告最后一行调用blockingMappedReduced的地方。
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'来自在线QT文档(http://doc.qt.nokia.com/4.7-snapshot/qtconcurrentmap.html#blockingMappedReduced)的原型如下:
T blockingMappedReduced ( const Sequence & sequence, MapFunction mapFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions = UnorderedReduce | SequentialReduce ) 恐怕我没有调试这方面的专业知识。任何帮助都将不胜感激。同样,由于我的C++技能不是专家,为了让我理解它,帮助必须是明确的(即实际的代码片段,而不是假设比我拥有更多知识的东西,比如“你的参数必须是一个常量引用”)。
提前感谢您的帮助。
发布于 2011-11-01 09:29:45
您的代码有一些与QtConcurrent无关的一般性问题需要修补。首先,你不应该限定构造函数,而不是:
// The Temp constructor
Temp::Temp(double randomInput, double resultingOutput)你应该简单地写:
// The Temp constructor
Temp(double randomInput, double resultingOutput)myClass也是如此。此外,main的函数签名应该始终返回一个返回值,尽管在C99和C++中,如果您想返回0,可以省略int语句。(然而,我总是明确地将return 0作为个人偏好的问题。)
What should main() return in C and C++?
至于你的QtConcurrent问题,有几个。首先,您的QList是整数类型,文档指出序列中的类型应该与映射函数的第一个参数匹配(其中有一个双精度型)。因此,QList需要更改为双精度,否则您的映射函数需要接受int。
您遇到的另一个问题是,您试图将指向成员函数的指针传递到只需要普通函数的槽中:
// Invoke the parallel map/reduce function
myClass myClassInstance;
double theAnswer = QtConcurrent::blockingMappedReduced(aList,
&myClass::mapFunction, &myClass::reduceFunction);请注意,除了声明之外,没有提到myClassInstance。在一般的case...working中,这并不像更改调用来使用&myClassInstance::mapFunction, &myClassInstance::reduceFunction那么容易。环顾四周的C++,你会发现没有一种通常可行的方法可以让对象适合函数调用的任何位置,即使它们被设计成像函数一样可调用:
Help with boost bind/functions
幸运的是,QtConcurrent不会把你逼入绝境。它预见了对函数对象的需求:
http://doc.qt.io/archives/qt-4.7/qtconcurrentmap.html#using-function-objects
但是,我们不应该深入研究如何实现这一点,我们应该考虑为什么你一开始就想把它们作为成员函数。Map/Reduce模型允许您定义自定义累加器和结果类型,这可以在没有任何麻烦的情况下获得您想要的东西。这里有一个更简单的版本,希望它能编译并让你更接近:
#include <qlist.h>
#include <qtconcurrentmap.h>
#include <cmath> // for sin()
#include <algorithm> // for min, max, etc.
#include <limits> // for numeric_limits
struct MapResult // same as class, but "public" by default
{
double input;
double output;
// must be "default constructible" due to guts of QtConcurrent :-/
// implementation artifact, don't worry about it affecting you...
MapResult () {}
MapResult (double input, double output) :
// initializing members like this is cleaner than this->x = x...
// and for certain members you HAVE to do it this way
input (input), output (output)
{
}
};
struct ReduceAccumulator // same as class, but "public" by default
{
MapResult largest;
ReduceAccumulator () :
// a better choice than 0 for an "uninitialized max" since
// any other double will be larger...but you really should
// probably accomodate a "no entries" case
largest (MapResult (0, std::numeric_limits<double>::min())
{
}
};
// pattern of return type should be "U", not "const U" according to docs
MapResult mapFunction(const double& input)
{
// no need to construct a named local var if you don't want to
// also no parentheses needed on return(x); ... return x; is fine
return MapResult (input, sin(input));
}
void reduceFunction(ReduceAccumulator& acc, const MapResult& oneResult)
{
if (oneResult.output > acc.largest.output) {
acc.largest = oneResult
}
}
int main(int argc, char* argv[])
{
QList<double> aList;
for (int count = 8; count > 0; --count)
{
aList.append(rand());
}
ReduceAccumulator answer = QtConcurrent::blockingMappedReduced(
aList, &mapFunction, &reduceFunction);
return 0;
}包括一些通用的C++注释,希望对您有所帮助。
UPDATE:他们提供的另一种方法确实使用了成员函数,但它做了一些与您试图编写的样式不同的假设。首先,它假设您的序列输入类型是一个类(double是"POD“或”普通旧数据“类型,并且没有方法分派)。则该参数是隐式的。
但请注意,如果您想使用这种技术,它将以一种特定的方式来样式化代码。以下是更改:
struct ReduceAccumulator
{
MapResult largest;
ReduceAccumulator () :
largest (MapResult(0, std::numeric_limits<double>::min())
{
}
// runs on non-const object, and drops first parameter (now implicit)
void reduceFunction(const MapResult& oneResult)
{
if (oneResult.output > largest.output) {
largest = oneResult
}
}
};
struct MyDouble {
double d;
MyDouble (double d) : d (d) {}
// as member it takes no arguments, and needs to run on const objects
MapResult mapFunction() const
{
return MapResult (d, sin(d));
}
};
int main(int argc, char* argv[])
{
// to use a member as mapFunction, must be a member of input sequence type
QList<MyDouble> aList;
for (int count = 8; count > 0; --count)
{
aList.append(MyDouble (rand()));
}
ReduceAccumulator theAnswer = QtConcurrent::blockingMappedReduced(
aList, &MyDouble::mapFunction, &ReduceAccumulator::reduceFunction);
}你可以选择和choose...in这种情况下,可能更好做的reduceFunction作为一个成员。但是更改输入序列类型有点难看,而且这不是为进程设置参数的正确位置--您需要一个函数对象。
(还要记住,映射函数可以获得的可写状态会破坏MapReduce的并行性。map操作实际上应该只通过其结果生成输出,因此它们保持独立...)
发布于 2011-11-01 16:07:15
HostileFork:再次感谢您的帮助。你让我回到了让我真正的代码工作的轨道上来。
为了完整起见,这里是我的原始示例,其中包含了使blockingMappedReduced正常工作所需的最少更改(但仍然存在我混乱的C++样式问题)。这就是我如何通过你的解决方案来理解什么是什么。它可能会帮助其他人区分哪些是blockingMappedReduced问题,哪些是C++问题:
#include "stdafx.h"
#include <qlist.h>
#include <qtconcurrentmap.h>
// My class for the map/reduce functions
class myClass
{
// 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;
// default Temp constructor
Temp()
{
};
// The Temp constructor
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()
{
this->maximumOutput = -1;
}
// The map function
static Temp myClass::mapFunction(const int& randomInput)
{
// For example, let's calculate the sine of the given random number
double resultingOutput = sin((double)randomInput);
// Construct the temporary structure to pass multiple values to the reduce function
Temp temp(randomInput, resultingOutput);
return(temp);
}
// The reduce function
static void myClass::reduceFunction(myClass& accumulator, const Temp& temp)
{
// For example, let's find the maximum computed sine value
if (temp.resultingOutput > accumulator.maximumOutput)
{
accumulator.maximumOutput = temp.resultingOutput;
accumulator.maximumInput = temp.randomInput;
}
}
};
// Main function
int 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 theAnswer = QtConcurrent::blockingMappedReduced(aList, &myClass::mapFunction, &myClass::reduceFunction);
return(0);
}https://stackoverflow.com/questions/7961043
复制相似问题