Qt C ++ lambda表达式不推导返回类型

时间:2017-03-18 20:08:40

标签: c++ qt lambda

我有一个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功能。

2 个答案:

答案 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;
}