QtConcurrent 错误:对非静态成员的引用

Posted

技术标签:

【中文标题】QtConcurrent 错误:对非静态成员的引用【英文标题】:QtConcurrent error: reference to non-static member 【发布时间】:2013-08-11 20:17:36 【问题描述】:

我在装有 OS-X 10.8.4 的 Mac 上运行 Qt 5.1 和 QtQuick 2.0。

我的 Qt-QML GUI 变得无响应,因为我用文件 I/O 操作阻塞了事件循环。解决它的常用方法是使用多线程,正如 Will Bickford 所讨论的 HERE。

为此,我尝试使用:

QtConcurrent::blockingMapped() 

这比使用显式 QFuture 对象更简单。我一直在阅读Qt docs 和cool examples 并得到以下代码工作(仿照example):

// NOTE: this all seems to work:
#include <QList>
#include <iostream>
#include "dataobject.h"
#include <QtConcurrent/QtConcurrentMap>

DataObject load(const QString &file) 
    std::cout << "File I/O in thread = " << QThread::currentThread() << std::endl;
    return DataObject anObject(file);


int main(int argc, char *argv[])

    ...

    // Create a list of filenames:
    int count = 5;
    QList<QString> allFiles;
    for (int i = 0; i < count; i++) 
        allFiles.append(QString("aFileName"));
    
    std::cout << "# of files = " << allFiles.size() << std::endl;

    QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles,load);
    std::cout << "# of objects = " << allTheDataObjects.size() << std::endl;

    ...

这里是 DataObject 的头文件和实现文件:

#include <QString>
class DataObject

public:
    DataObject();
    DataObject(QString filename);
    QString theFileName;
;

#include "dataobject.h"

DataObject::DataObject() 
    theFileName = QString("no file");

DataObject::DataObject(QString filename) 
    theFileName = filename;
    //...
    // Do file I/O stuff (slow) ...

这不是很现实,但可以作为一个简单的草图来说明我在下面遇到的问题。

当我尝试将 QtConcurrent::blockingMapped() 封装在一个额外的“datamodel.h”类中时会出现问题:

#include "dataobject.h"
class DataModel

public:
    DataModel();
    void runConcurrent();
    DataObject load(const QString& fileList);
;

#include "datamodel.h"
#include <QtConcurrent/QtConcurrentMap>
#include <iostream>

DataModel::DataModel() 
DataObject DataModel::load(const QString &file) 
    std::cout << "File I/O in thread = " << QThread::currentThread() << std::endl;
    return DataObject anObject(file);

void DataModel::runConcurrent() 
    // Create a list of filenames:
    int count = 5;
    QList<QString> allFiles;
    for (int i = 0; i < count; i++)
        allFiles.append(QString("dummyFileName"));
    QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles, this->load);
    std::cout << "# of objects = " << allTheDataObjects.size() << std::endl;

然后 main() 就变成了(注意我也把 load() 方法移到了 DataModel 类中):

#include <QList>
#include <iostream>
#include "dataobject.h"
#include "datamodel.h"
#include <QtConcurrent/QtConcurrentMap>

int main(int argc, char *argv[])

    ...

    DataModel theModel;
    theModel.runConcurrent();

    ...

但是现在出现编译错误:

datamodel.cpp: error: reference to non-static member function must be called:
QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles, this->load);

我无法通过初始化 DataObject 或 DataModel 实例来修复编译器错误(以便可以看到非静态成员函数),并且不确定还可以尝试什么。

接下来我怀疑这可能是由于设置 QtConcurrent 参数时“函子”绑定的问题(我没有安装 boost,所以没有使用 boost::bind)所以我尝试了使用 C++ 11 的 Mat's suggestion lambdas 通过替换:

this->load

与:

[this](const QString& file)load(file);

给出代码:

QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles, 
                                       [this](const QString& file)load(file););

现在我不再得到非静态成员错误,而是出现了一个新错误(指向上面的行):

datamodel.cpp: error: expected expression:

我真的在这个问题上陷入了困境,这可能是一个简单的错误,但我无法解决它。

有人可以帮忙吗?

【问题讨论】:

【参考方案1】:

显然您不使用具有 lambda 表达式的 C++11。所以使用 STL 或 Boost 中的绑定或创建函数对象。

QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles, 
                                   std::bind1st(std::mem_fun(&DataModel::load), this));

好的,以上解决方案不能与引用一起使用(知道错误)。定义函子(或使用 Boost::bind):

class LoadDataModel /*: public std::unary_function<QString, DataObject>*/ 
public:
    LoadDataModel(DataModel *p) : d(p) 

    DataObject operator()(const QString &s) const 
        return d->load(s);
    
private:
    DataModel *d;


QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles, LoadDataModel(this));

【讨论】:

您的建议生效了吗?添加 #include 后,我在上面尝试了您的代码,但现在得到了一堆其他非描述性错误,例如 stl_function.h:411: error: multiple overloads of 'operator()' ... 等等, 对于许多行。还有什么想法吗?感谢所有建议! 我忘了引用有问题:***.com/a/7823004/1387438,所以在这种情况下,解决问题的最快方法是定义函子。 我将致力于定义函子,但我们是否确定函子是问题所在?请注意,“load”已经是一个一元函数,因此我们不需要绑定其他参数。还要注意,在 QtConcurrent::blockingMapped() 被打包到 DataModel 类之前,这段代码运行良好(如上所示),所以本质上,如果函子绑定是问题,为什么没有 DataModel 类它不会中断?跨度> 无负载不是一元函数。要调用它,您总是需要两个参数:this 写在函数名之前,fileList 写在函数名之后。没有对象就不能调用这个函数。 谢谢,这是有道理的,但它在没有 DataModel 类的情况下运行良好似乎仍然很奇怪。【参考方案2】:

好的,开始工作了。

如果这可以使那些不想弄乱绑定或编写自己的“函子”的人受益(下面的方法更简单):

首先使用 datamodel.h 文件中的静态类型来实现“加载”功能:

static DataObject load(const QString& fileList);

这是因为可以调用 C++ 类的静态函数而无需实例化对象。

那么,在datamodel.cpp文件中,就是这么简单:

DataModel::load 

给予:

QList<DataObject> allTheDataObjects = 
                      QtConcurrent::blockingMapped(allFiles, DataModel::load);

然后代码按预期运行。

【讨论】:

以上是关于QtConcurrent 错误:对非静态成员的引用的主要内容,如果未能解决你的问题,请参考以下文章

Qt 如何在 QtConcurrent 中将指针绑定到非静态成员函数?

C#非静态的字段、方法或属性要求对象引用

对非共享成员的引用需要在调用公共子时发生对象引用

无法从 HibernateUtil 类型对非静态方法 getSessionFactory() 进行静态引用

无法对非静态方法 getAssets() 进行静态引用 - 无法在片段中播放音频

QtConcurrent 给出错误