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

Posted

技术标签:

【中文标题】Qt 如何在 QtConcurrent 中将指针绑定到非静态成员函数?【英文标题】:How does Qt bind pointers-to-non-static-member-functions in QtConcurrent? 【发布时间】:2011-11-16 17:25:32 【问题描述】:

来自QtConcurrent documentation:

QByteArray bytearray = "hello world";
QFuture<QList<QByteArray> > future = QtConcurrent::run(bytearray, &QByteArray::split), ',');
...
QList<QByteArray> result = future.result();

上面的代码 sn-p 似乎以类似于std::tr1::bind 的方式绑定一个函数(std::bind for > C++11)。也就是说,它采用非静态成员函数 (QByteArray::split()) 并(稍后)在它所属的对象的特定实例上调用它(我们提供为 bytearray)。

Qt 是如何做到这一点的?是在幕后使用std::tr1::bind 还是boost::bind

The documentation 也指代您使用 std::tr1boost 的情况,但我不完全理解 绑定函数 在这种情况下的含义。上述情况实际上是否与您可能使用tr1boost 的其他情况不同/更专业/更简单?

我试图通过源头找到自己的方式,但很快就迷路了!

【问题讨论】:

【参考方案1】:

我将尝试一个自我回答,因为现有的答案(非常感谢@Mike Brown 和@skyhisi)奠定了基础,但不解决这个具体案例......

来源:

QtConcurrent::run(...) :

template <typename T, typename Class>
QFuture<T> run(const Class &object, T (Class::*fn)())

  return (new QT_TYPENAME SelectStoredMemberFunctionCall0<T, Class>::type(fn, object))->start();

SelectStoredMemberFunctionCall0

template <typename T, typename Class>
struct SelectStoredMemberFunctionCall0

  typedef typename SelectSpecialization<T>::template
    Type<StoredMemberFunctionCall0    <T, Class>,
      VoidStoredMemberFunctionCall0<T, Class> >::type type;
;

VoidStoredMemberFunctionCall0

template <typename T, typename Class>
class VoidStoredMemberFunctionCall0 : public RunFunctionTask<T>

public:
  VoidStoredMemberFunctionCall0(T (Class::*_fn)() , const Class &_object)
  : fn(_fn), object(_object) 

  void runFunctor()
  
    (object.*fn)();
  
private:
  T (Class::*fn)();
  Class object;
;

鉴于上述情况,我可以看到 Qt 在 normal way 中存储了一个指向成员函数的指针,但是通过将其装饰在模板中,否则会被忽视,从而产生了泛型的错觉。

VoidStoredMemberFunctionCall0::object 的类型以及VoidStoredMemberFunctionCall0::fn 的签名都在上面传递给QtConcurrent::run 的参数中指定。

说实话,我什至不知道这种“隐式”模板化是可能的。有人可以推荐进一步阅读吗?

【讨论】:

我发现The C++ Programming Language 这本书对于理解 C++ 非常有用。 C++ FAQ Templates 页面对模板的许多方面也有很好的解释。【参考方案2】:

C++ FAQ 很好地解释了Pointers to member functions 并解释了陷阱。

在某些时候会有类似的一行:

ret_val = obj_ptr->*func_ptr(param);

但它会被封装在模板中以允许传递任何对象类型和参数类型,并且其中也会混杂线程调度。

【讨论】:

【参考方案3】:

您正在传递函数指针和声明函数的类的实例。调用它就像从对象中取消引用函数指针一样简单。 This *** Question 给出答案

【讨论】:

我知道QtConcurrent::run 必须使用指向成员函数的指针,我只是不明白它如何在函数返回类型、参数和对象时存储指针/调用函数其中它的成员不是在QtConcurrent 中硬编码,而是从提供给run(...) 的参数中提取。

以上是关于Qt 如何在 QtConcurrent 中将指针绑定到非静态成员函数?的主要内容,如果未能解决你的问题,请参考以下文章

qt 创建线程

使用 QtConcurrent 在 QT 中进行多线程

Qt文档阅读笔记-QtConcurrent Progress Dialog Example解析

Qt多线程:QtConcurrent + QFuture + QFutureWatcher

Qt基础之十六:QtConcurrent和QThreadPool

Qt基础之十六:QtConcurrent和QThreadPool