Опорный уровень часть 2 - PullRequest
0 голосов
/ 04 июня 2011

Развернувшись по этому вопросу , похоже, я не предоставил достаточно подробностей.

У меня есть объект с именем CallbackObject, предназначенный для хранения экземпляра объекта, а также информации о том, какую функцию вызывать, и параметров, передаваемых во время вызова.

template <typename objectType,
          typename memberFunctionPtrType,
          typename memberFcnArg1Type>
struct CallbackObject1
{
  objectType obj ;
  memberFunctionPtrType fcnPtr ;
  memberFcnArg1Type arg1 ;

  CallbackObject1(objectType iObj,
                  memberFunctionPtrType iFcnPtr,
                  memberFcnArg1Type iArg1 )
  {
    obj = iObj ;
    fcnPtr = iFcnPtr ;
    arg1 = iArg1 ;
  }

  void exec()
  {
    <b>(obj.*fcnPtr)( arg1 ) ;</b>
  }
} ;

Пример использования:

struct Point
{
  float x,y ;
  void print( int numTimes )
  {
    for( int i = 0 ; i < numTimes ; i++ )
      printf( "%f %f\n", x, y ) ;
  }
} ;

typedef void (Point::* PointPrintFcnType)( int ) ;

int main()
{
  Point p ;
  p.x=p.y=1;

  CallbackObject1<Point, PointPrintFcnType, int> ocall( p, &Point::print, 5 );
  ocall.exec() ;
}

Единственная проблема, с которой я сталкиваюсь, это то, что если objectType является типом указателя, то (obj.*fcnPtr) терпит неудачу, поскольку он должен действительно прочитать ( (*obj).*fcnPtr) или (obj->*fcnPtr), если obj является указателем.

Теперь у меня есть одно решение, где я определяю другой Класс CallbackObject следующим образом:

template <typename pObjectType,
          typename memberFunctionPtrType,
          typename memberFcnArg1Type>
struct CallbackPObject1
{
  pObjectType obj ;
  memberFunctionPtrType fcnPtr ;
  memberFcnArg1Type arg1 ;

  CallbackPObject1(pObjectType iObj,
                  memberFunctionPtrType iFcnPtr,
                  memberFcnArg1Type iArg1 )
  {
    obj = iObj ;
    fcnPtr = iFcnPtr ;
    arg1 = iArg1 ;
  }

  void exec()
  {
    <b>(obj->*fcnPtr)( arg1 ) ;</b>
  }
} ;

Но в лучшем случае это грубовато, а в худшем - трудно использовать, если кто-то еще использует этот код, ему придется создать объект Callback другого типа, если используемый тип объекта на самом деле является указателем.

Есть ли способ обойти это?

Ответы [ 3 ]

1 голос
/ 04 июня 2011

Вот пример вспомогательной функции, предполагающей возврат void, один аргумент и отсутствие необходимости обрабатывать более одного уровня косвенности:

template <typename T, typename F, typename A>
inline void invoke(T& obj, F func, const A& arg)
{
    (obj.*func)(arg);
}

template <typename T, typename F, typename A>
inline void invoke(T* obj, F func, const A& arg)
{
    (obj->*func)(arg);
}

Если вам нужно обработать более одного уровня косвенности, вы можете заменить вторую функцию следующим:

template <typename T, typename F, typename A>
inline void invoke(T* obj, F func, const A& arg)
{
    invoke(*obj, func, arg);
}

Это будет рекурсивно отбрасывать уровни косвенности до тех пор, пока вы не получите что-то, на чем вы можете вызывать функцию-член.

Затем вы можете написать свою exec() функцию следующим образом:

void exec()
{
    invoke(obj, fcnPtr, arg1);
}
0 голосов
/ 04 июня 2011

Хорошо, применяем подход "перегрузки" к предыдущему вопросу Я получаю

template <typename objectType,
          typename memberFunctionPtrType,
          typename memberFcnArg1Type>
struct CallbackObject1 : public Callback
{
  objectType obj ;
  objectType *pObj ;
  memberFunctionPtrType fcnPtr ;
  memberFcnArg1Type arg1 ;

  CallbackObject1(objectType iObj,
                  memberFunctionPtrType iFcnPtr,
                  memberFcnArg1Type iArg1 )
  {
    obj = iObj ;
    pObj = 0 ;
    fcnPtr = iFcnPtr ;
    arg1 = iArg1 ;
  }

  CallbackObject1(objectType *iObj,
                  memberFunctionPtrType iFcnPtr,
                  memberFcnArg1Type iArg1 )
  {
    pObj = iObj ;
    fcnPtr = iFcnPtr ;
    arg1 = iArg1 ;
  }

  void exec()
  {
    if( pObj )
      (pObj->*fcnPtr)( arg1 ) ;
    else
      (obj.*fcnPtr)( arg1 ) ;
  }
} ;

Использование

  typedef void (Point::* PointPrintFcnType)( int ) ;

  Point p ;
  p.x=p.y=1;

  CallbackObject1<Point, PointPrintFcnType, int> ocall( p, &Point::print, 5 );
  ocall.exec() ;

  CallbackPObject1<Point*, PointPrintFcnType, int> ocallP( &p, &Point::print, 2 );
  ocallP.exec() ;

Работает достаточно хорошо, но внутри не так чисто, как хотелось бы.

0 голосов
/ 04 июня 2011

Используйте объект полиморфной функции, такой как boost::function, в сочетании с функциями, производящими функторы, такими как boost::bind.Это гораздо лучшее решение - гениальность возникает, когда создается функтор, а не когда он вызывается, и любой функциональный объект, который можно вызвать с правильной сигнатурой, может быть вызван.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...