Question

From the QtConcurrent documentation:

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

The code snippet above appears to be binding a function in a similar way to std::tr1::bind (std::bind for > C++11). That is to say it's taking a non-static member function (QByteArray::split()) and (at some point later) calling it on the specific instance of the object of which it's a member (which we've supplied as bytearray).

How does Qt achieve this? Is it using std::tr1::bind or boost::bind somewhere behind the scenes?

The documentation does also refer to a case where you would use std::tr1 or boost instead, but I don't fully understand what it means by a bound function in that context. Is the situation above in fact different/more specialised/simpler than other situations where you might otherwise use tr1 or boost?

I've tried to make my way through the source but am getting lost very quickly!

Was it helpful?

Solution

I'm going to attempt a self answer, as the existing answers (many thanks to @Mike Brown and @skyhisi) lay the groundwork but don't address this specific case...

From the source:

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

Given the above, I can see that Qt stores a pointer-to-member-function in the normal way, but by dressing it up in templates which would otherwise go unnoticed, the illusion of generic-ness is created.

The type of VoidStoredMemberFunctionCall0::object as well as the signature of VoidStoredMemberFunctionCall0::fn are all specified above in the arguments passed to QtConcurrent::run.

I wasn't aware that this 'implicit' templatization was even possible, to be honest. Would anybody be able to recommend further reading?

OTHER TIPS

The C++ FAQ explains Pointers to member functions very well and explains the pitfalls.

At some point there would be a line similar to:

ret_val = obj_ptr->*func_ptr(param);

But it will be wrapped up in templates to allow passing any object type and parameter type, and there will be the thread dispatching mixed up in there as well.

You're passing a Function Pointer and an Instance of the Class the function was declared on. Invoking it is as simple as dereferencing the function pointer from the object. This StackOverflow Question shows the answer

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top