Как Qt связывает указатели на нестатические функции-члены в QtConcurrent? - PullRequest
2 голосов
/ 16 ноября 2011

Из документации QtConcurrent :

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

Приведенный выше фрагмент кода, похоже, связывает функцию аналогично std::tr1::bind (std::bind для> C ++ 11). То есть он принимает нестатическую функцию-член (QByteArray::split()) и (в какой-то момент позже) вызывает ее для конкретного экземпляра объекта, членом которого он является (который мы предоставили как bytearray).

Как Qt достигает этого? Использует ли он std::tr1::bind или boost::bind где-то за кадром?

Документация также относится к случаю, когда вместо этого вы бы использовали std::tr1 или boost, но я не до конца понимаю, что это означает под связанной функцией в этом контексте. Является ли описанная выше ситуация фактически другой / более специализированной / более простой, чем другие ситуации, в которых вы могли бы иначе использовать tr1 или boost?

Я пытался пробраться через источник, но очень быстро заблудился!

Ответы [ 3 ]

2 голосов
/ 17 ноября 2011

Я собираюсь попытаться ответить самостоятельно, поскольку существующие ответы (большое спасибо @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 хранит функцию указателя на член обычным образом , но, перераспределяя ее в шаблоны, которые в противном случае остались бы незамеченными, иллюзия Несс создан.

Тип VoidStoredMemberFunctionCall0::object, а также подпись VoidStoredMemberFunctionCall0::fn указаны выше в аргументах, передаваемых QtConcurrent::run.

Я не знал, что эта «неявная» шаблонизация была даже возможна, если честно. Кто-нибудь сможет порекомендовать дальнейшее чтение?

1 голос
/ 16 ноября 2011

FAQ по C ++ объясняет Указатели на функции-члены очень хорошо и объясняет подводные камни.

В какой-то момент может появиться строка, похожая на:

ret_val = obj_ptr->*func_ptr(param);

Но он будет заключен в шаблоны, позволяющие передавать любой тип объекта и тип параметра, и там также будет перепутана диспетчеризация потоков.

0 голосов
/ 16 ноября 2011

Вы передаете указатель на функцию и экземпляр класса, для которого была объявлена ​​функция.Вызывать это так же просто, как разыменовать указатель на функцию из объекта. Этот вопрос StackOverflow показывает ответ

...