我有一个lambda表达式,它从另一个类包装成员函数,所以我可以在其他类中使用它,就像它们自己的成员一样。
auto fun = [this] (const QString& imageName) -> QImage {
typedef QImage result_type;
return _mapper(imageName);
};
_mapper 仿函数来自另一个类,并返回QImage
。
现在我的问题是我使用它的编译器或Qt函数不喜欢这个并且不能推断出结果类型。
QtConcurrent/qtconcurrentmapkernel.h:124: error: no type named ‘result_type’ in ‘struct *mystruct_ptr*::<lambda(const class QString&)>’
IntermediateResults<typename MapFunctor::result_type> results;
^
但更传统的std::bind
有效:
auto fun_binded = std::bind(&Mapper::operator(), &_mapper, std::placeholders::_1);
所以问题:lambda有什么问题?
也许我应该提一下我使用它的背景:
QtConcurrent::mappedReduced<QList<QImage>>(*image_container*, fun, fun_reduce))
fun_reduce
类似地完成,但它具有void
功能。
答案 0 :(得分:1)
问题是lambda没有定义库在result_type
中使用的成员类型typename MapFunctor::result_type
,但是std::function
会这样做。
库需要定义result_type
。
所以要么坚持std::bind
,要么将你的lambda包装在std :: function中:
// This will convert the lambda to an std::function
std::function<QImage(const QString&)> fun =
[this](const QString& imageName) { return _mapper(imageName);};
或者编写定义了此类型的自定义结构。
struct MyFunctor
{
using result_type = QImage;
// Here you must store a pointer or a ref to the "owner" (this)
QImage operator()(const QString& imageName) {
return owner->mapper(imageName);
}
};
答案 1 :(得分:0)
您可以使用std::function
,但有不必要的开销。我建议使用包装器:
#include <QtCore>
#include <QtConcurrent/QtConcurrent>
#include <type_traits>
struct Item
{
QDateTime timestamp;
QByteArray json;
};
template< typename Result, typename Functor >
struct FunctorWithResultTypedef
: std::decay_t< Functor >
{
using result_type = Result;
FunctorWithResultTypedef(Functor & functor)
: std::decay_t< Functor >{std::forward< Functor >(functor)}
{ ; }
};
template< typename Result, typename Functor >
FunctorWithResultTypedef< Result, Functor >
addResultTypedef(Functor && functor)
{
return {functor};
}
int main(int argc, char * argv[])
{
QDir jsonDir{R"(input/)"};
auto pattern = QStringLiteral("yyyy-MM-dd'T'HH'%1'mm'%1'ss'.'zzz").arg(QChar(0xF03A));
auto fileInfos = jsonDir.entryInfoList(QStringList{} << "*.json", (QDir::Readable | QDir::Files));
auto map = [&pattern] (const QFileInfo & fileInfo) -> Item
{
auto dateTime = QDateTime::fromString(fileInfo.completeBaseName().chopped(3), pattern);
Q_ASSERT(dateTime.isValid());
QFile file{fileInfo.filePath()};
if (!file.open(QFile::ReadOnly)) {
qFatal("unable to open file %s to read", qPrintable(file.fileName()));
}
QJsonParseError jsonParseError;
auto jsonDocument = QJsonDocument::fromJson(file.readAll(), &jsonParseError);
if (jsonDocument.isNull()) {
qFatal("wrong JSON: %1", qPrintable(jsonParseError.errorString()));
}
return {dateTime, jsonDocument.toJson(QJsonDocument::Indented)};
};
using ResultType = QByteArray;
auto reduce = [] (ResultType & json, const Item & item)
{
json.append(item.json);
};
auto result = QtConcurrent::blockingMappedReduced< ResultType >(fileInfos, addResultTypedef< Item >(map), addResultTypedef< ResultType >(reduce), QtConcurrent::SequentialReduce);
{
QFile file{R"(output.json)"};
if (!file.open(QFile::Truncate | QFile::WriteOnly)) {
qFatal("unable to open file %s to write", qPrintable(file.fileName()));
}
file.write(result);
}
return EXIT_SUCCESS;
}