aria中的ArFunctor真相

来源:互联网 发布:扫地老僧软件 编辑:程序博客网 时间:2024/05/16 23:43

貌似boost中有仿函数一说??有待学习。
ArFunctor的解释为
“ Functors which refer to these callbacks will be passed to the DriverClass, An object which allows storing a generalized reference to a method with an object instance to call later (used for callback functions)

安装包内html中,Functor 的解释
Functors are used throughout ARIA. Functor is short for function pointer. A Functor lets you call a function without knowing the declaration of the function. Instead, the compiler and linker figure out how to properly call the function.
Functor 贯穿使用在Aria中,Functor 指向函数指针。Functor 在没有函数声明的情况下调用函数,相反,编译器和链接器会知道并调用函数。
Function pointers are fully supported by the C language. C++ treats function pointers like C, but to call class methods, an instance object is required, as well as type information about the class. Therefore, ARIA contains a set of template classes to contain this information.
C++用类似C的方式处理函数指针。要调用类的方法,类 和类的实例对象是必须的。因此,Aria包含了一组模板类来包含这些信息。
ARIA makes heavy use of ArFunctors as “callback” functions. To instantiate a functor, you first need to identify how many arguments the function needs and if it returns a value. Many times a pointer to the abstract ArFunctor base class is used, which can be invoked with no arguments and no return value. Subclasses are used for functions with different numbers of arguments and return values. ArFunctor1, ArFunctor2, ArRetFunctor, ArRetFunctor1, and ArRetFunctor2 for example. When invoked, the arguments may be supplied which are passed to the target function or method, and a return value may also be given. The types for the arguments and/or return value are given as template arguments.
Aria中使用arfunctor作为回调函数。实例化一个functor,你首先要考虑函数需要多少个参数,是否有返回值。
ArFunctor 无惨 无返回值
ArFunctor1 ArRetFunctor1 带参 带返回值,这时候用模板参数来实现。
When creating a functor object, however, you must also provide the type and instance of an object to invoke the method of; or explicitly state that the function is a class-less global function.
Do this by using one of the concrete base classes of ArFunctor instead of the abstract classes: ArFunctorC, ArFunctor1C, ArFunctor2C, ArRetFunctorC, ArRetFunctor1C, ArRetFunctor2C, ArGlobalFunctor, ArGlobalFunctor1, etc.
EXAMPLE:

class ExampleClass {public:    void aFunction(int n);};...ExampleClass obj;ArFunctor1C<ExampleClass, int> functor(&obj, &ExampleClass::aFunction);            类型           参数类型      类实例  类内函数名(函数指针)...functor.invoke(42);

ExampleClass is a class which contains a function called aFunction(). The functor functor is declared as an ArFunctor1C, a functor which invokes a class method and takes one argument. The template parameters specify the type of the class (ExampleClass) and the type of the method argument (int). functor is then initialized with a pointer to the ExampleClass instance to call the method on, and a pointer to the class method to call. When a functor is contained within the class, it is typcially initialized in the constructor, giving this as the object instance.
ExampleClass 自定义的类,类内含有一个aFunction(int)函数。
ArFunctor1C 实例一个对象, 该对象保存了ExampleClass::aFunction(int)的函数指针。
A functor must be initialized with the method to call and, if a “C” functor, a class instance. An unitilialized functor will crash at runtime when invoked.
一个Functor 初始化时必须有被调用的方法,如果带“C”,说明类的实例。(带C指的是指针类内方法的函数指针)
It is also possible to give values for the method arguments in the functor initialization, see ArFunctor documentation for details.

Once the functor object is created in this fashion, it can now be passed to another function or object that wants a callback functor. And the method ExampleClass::aFunction() will be called on the object obj when the functor is invoked.
functor创建后,他即可被传递到那些需要一个回调functor的函数或者对象,如当functor被invoke时,obj::aFunction(int)就会被调用。
To invoke a functor, simply call the invoke() function on the functor. If it takes arguments, call invoke() with those arguments. If the functor has a return value, call invokeR. The return value of the function will be passed back through the invokeR() function. If the functor was initialized with argument values, and invoke() is called without argument values, the argument values provided at initialization are passed.

///////////////////////////////
An object which allows storing a generalized reference to a method with an object instance to call later (used for callback functions)

Functors are meant to encapsulate the idea of a pointer to a function which is a member of a class. To use a pointer to a member function, you must have a C style function pointer, ‘void(Class::*)()’, and a pointer to an instance of the class in which the function is a member of. This is because all non-static member functions must have a ‘this’ pointer. If they dont and if the member function uses any member data or even other member functions it will not work right and most likely crash. This is because the ‘this’ pointer is not the correct value and is most likely a random uninitialized value. The virtue of static member functions is that they do not require a ‘this’ pointer to be run. But the compiler will never let you access any member data or functions from within a static member function.

Because of the design of C++ never allowed for encapsulating these two pointers together into one language supported construct, this has to be done by hand. For conviences sake, there are functors (ArGlobalFunctor, ArGlobalRetFunctor) which take a pure C style function pointer (a non-member function). This is in case you want to use a functor that refers to a global C style function.

Aria makes use of functors by using them as callback functions. Since Aria is programmed using the object oriented programming paradigm, all the callback functions need to be tied to an object and a particular instance. Thus the need for functors. Most of the use of callbacks simply take an ArFunctor, which is the base class for all the functors. This class only has the ability to invoke a functor. All the derivitave functors have the ability to invoke the correct function on the correct object.

Because functions have different signatures because they take different types of parameters and have different number of parameters, templates were used to create the functors. These are the base classes for the functors. These classes encapsulate everything except for the class type that the member function is a member of. This allows someone to accept a functor of type ArFunctor1 which has one parameter of type ‘int’. **But they never have to know that the function is a member function of class ‘SomeUnknownType’. These classes are:
ArFunctor, ArFunctor1, ArFunctor2, ArFunctor3 ArRetFunctor, ArRetFunctor1, ArRetFunctor2, ArRetFunctor3
These 8 functors are the only thing a piece of code that wants a functor will ever need. But these classes are abstract classes and can not be instantiated.** On the other side, **the piece of code that wants to be called back will need the functor classes that know about the class type. These functors are:
ArFunctorC, ArFunctor1C, ArFunctor2C, ArFunctor3C ArRetFunctorC, ArRetFunctor1C, ArRetFunctor2C, ArRetFunctor3C**

These functors are meant to be instantiated and passed of to a piece of code that wants to use them. That piece of code should only know the functor as one of the functor classes without the ‘C’ in it.
不带C的是抽象基类,带C的是可被实例化的类内成员函数指针的functor
Note that you can create these FunctorC instances with default arguments that are then used when the invoke is called without those arguments… These are quite useful since if you have a class that expects an ArFunctor you can make an ArFunctor1C with default arguments and pass it as an ArFunctor… and it will get called with that default argument, this is useful for having multiple functors use the same function with different arguments and results (just takes one functor each).

Functors now have a getName() method, this is useful as an aid to debugging, allowing you to display the name of some functor being used
///////////////////////////////

一般类的私有成员函数中的函数指针会用“ArFunctor”.
而在例程中我们看到的是“ArFunctorC”C——callback,即为回调函数的指定。

Aria中一些命名习惯的含义 ArFunctor                                   基类      ArFunctor1                       含一个参数的函数指针      ArFunctor2        ArGloablFunctor      ArRetGlobalFunctor                   含?个参数的函数指针以上为抽象类,不可被实例化。     ArFunctorC                    指明一个类中成员函数为回掉函数,声明为一个指针      ArFunctor1C                   指明为带一个参数的函数指针      ArRetFunctorC                 带返回值、不带参数的函数指针      ArRetFunctor1C                带返回值,带一个int参数的函数指针      ArGlobalFunctorC              区别为函数指针指向的是全局函数,而非类的成员函数

functorExample.cpp

#include <string>#include "Aria.h"/*  This is a class that has some callback methods. Functors which refer to these  callbacks will be passed to the DriverClass.  *///以下类和全局函数,为被调用的部分class CallbackContainer{public:  void callback1();  void callback2(int i);  bool callback3(const char *str);};void CallbackContainer::callback1(){  printf("CallbackContainer::callback1 called.\n");}void CallbackContainer::callback2(int i){  printf("CallbackContainer::callback2 called with argument of '%d'\n", i);}bool CallbackContainer::callback3(const char *str){  printf("CallbackContainer::callback3 called with argument of '%s'.\n", str);  return(true);}/*  * Functors can also invoke global functions. */void globalCallback(){  printf("globalCallback() called.\n");}/*  This is a "driver" class. It takes three functors of different types and  will invoke the three functors. This is a typical use of  functors: to pass information or event notifications between loosely  coupled objects.*///以下部分由functor进行调用class DriverClass{public:  void invokeFunctors();  void setCallback1(ArFunctor *func) {myFunc1=func;}  void setCallback2(ArFunctor1<int> *func) {myFunc2=func;}  void setCallback3(ArRetFunctor1<bool, const char *> *func) {myFunc3=func;}protected://类内用来接收回调函数指针的**基类**,外界的ArFunctorC将类对象的成员函数指针传入进来。  ArFunctor *myFunc1;  ArFunctor1<int> *myFunc2;  ArRetFunctor1<bool, const char *> *myFunc3;};void DriverClass::invokeFunctors(){  bool ret;  printf("Invoking functor1... ");  myFunc1->invoke();  printf("Invoking functor2... ");  myFunc2->invoke(23);  /*     For functors with return values, use invorkeR() instead of invoke()     to get the return value.  The invoke() function can also be used to invoke     the functor, but the return value is lost.  (And is a possible source     of memory leaks if you were supposed to free a pointer returned.)  */  printf("Invoking functor3... ");  ret=myFunc3->invokeR("This is a string argument");  if (ret)    printf("\t-> functor3 returned 'true'\n");  else    printf("\t-> functor3 returned 'false'\n");}int main(){  CallbackContainer cb;//实例化对象的成员对象指针  ArFunctorC<CallbackContainer> functor1(cb, &CallbackContainer::callback1);  ArFunctor1C<CallbackContainer, int> functor2(cb, &CallbackContainer::callback2);  ArRetFunctor1C<bool, CallbackContainer, const char *>    functor3(cb, &CallbackContainer::callback3); //传入functor     driver.setCallback1(&functor1);  driver.setCallback2(&functor2);  driver.setCallback3(&functor3); // 回调  driver.invokeFunctors();   /* You can make functors that target global functions too. */  ArGlobalFunctor globalFunctor(&globalCallback);  printf("Invoking globalFunctor... ");  globalFunctor.invoke();  /* You can also include the values of arguments in an ArFunctor object, if you   * want to use the same value in every invocation of the functor.   */  ArFunctor1C<CallbackContainer, int> functor4(cb, &CallbackContainer::callback2, 42);  printf("Invoking functor with constant argument... ");  functor4.invoke();  /* Functors can be downcast to parent interface classes, as long as their invocation   * does not require arguments.   */  ArFunctor* baseFunctor = &functor4;  printf("Invoking downcast functor... ");  baseFunctor->invoke();  return(0);}

例子2DirectMotionExample.cpp:

#include "Aria.h"/*  This is a connection handler class, to demonstrate how to run code in  response to events such as the program connecting an disconnecting  from the robot.*///程序建立连接、连接失败、断链的“事件”时,被调用**class ConnHandler**{public:  // Constructor  ConnHandler(ArRobot *robot);  // Destructor, its just empty  ~ConnHandler(void) {}  // to be called if the connection was made  void connected(void);  // to call if the connection failed  void connFail(void);  // to be called if the connection was lost  void disconnected(void);protected:  // robot pointer  ArRobot *myRobot;  // the functor callbacks  ArFunctorC<ConnHandler> myConnectedCB;  ArFunctorC<ConnHandler> myConnFailCB;  ArFunctorC<ConnHandler> myDisconnectedCB;};//**构造函数,该构造函数将ArFunctor和对应调用函数关联。并将该回调函数赋给ArRobot,机器人在这几个事件的时候,自动回调。**ConnHandler::ConnHandler(ArRobot *robot) :  myConnectedCB(this, &ConnHandler::connected),    myConnFailCB(this, &ConnHandler::connFail),  myDisconnectedCB(this, &ConnHandler::disconnected){  myRobot = robot;  myRobot->addConnectCB(&myConnectedCB, ArListPos::FIRST);  myRobot->addFailedConnectCB(&myConnFailCB, ArListPos::FIRST);  myRobot->addDisconnectNormallyCB(&myDisconnectedCB, ArListPos::FIRST);  myRobot->addDisconnectOnErrorCB(&myDisconnectedCB, ArListPos::FIRST);}// just exit if the connection failedvoid ConnHandler::connFail(void){  printf("directMotionDemo connection handler: Failed to connect.\n");  myRobot->stopRunning();  Aria::exit(1);  return;}// turn on motors, and off sonar, and off amigobot sounds, when connectedvoid ConnHandler::connected(void){  printf("directMotionDemo connection handler: Connected\n");  myRobot->comInt(ArCommands::SONAR, 0);  myRobot->comInt(ArCommands::ENABLE, 1);  myRobot->comInt(ArCommands::SOUNDTOG, 0);}// lost connection, so just exitvoid ConnHandler::disconnected(void){  printf("directMotionDemo connection handler: Lost connection, exiting program.\n");  Aria::exit(0);}int main(int argc, char **argv) {  Aria::init();  ArArgumentParser argParser(&argc, argv);  argParser.loadDefaultArguments();  ArRobot robot;  ArRobotConnector con(&argParser, &robot);  // the connection handler from above  ConnHandler ch(&robot);  if(!Aria::parseArgs())  {    Aria::logOptions();    Aria::exit(1);    return 1;  }  if(!con.connectRobot())  {    ArLog::log(ArLog::Normal, "directMotionExample: Could not connect to the robot. Exiting.");    if(argParser.checkHelpAndWarnUnparsed())     {      Aria::logOptions();    }    Aria::exit(1);    return 1;  }  ArLog::log(ArLog::Normal, "directMotionExample: Connected.");  if(!Aria::parseArgs() || !argParser.checkHelpAndWarnUnparsed())  {    Aria::logOptions();    Aria::exit(1);  }  // Run the robot processing cycle in its own thread. Note that after starting this  // thread, we must lock and unlock the ArRobot object before and after  // accessing it.  robot.runAsync(false);  // Send the robot a series of motion commands directly, sleeping for a   // few seconds afterwards to give the robot time to execute them.  printf("directMotionExample: Setting rot velocity to 100 deg/sec then sleeping 3 seconds\n");  robot.lock();  robot.setRotVel(100);  robot.unlock();  ArUtil::sleep(3*1000);  printf("Stopping\n");  robot.lock();  robot.setRotVel(0);  robot.unlock();  ArUtil::sleep(200);  printf("directMotionExample: Telling the robot to go 300 mm on left wheel and 100 mm on right wheel for 5 seconds\n");  robot.lock();  robot.setVel2(300, 100);  robot.unlock();  ArTime start;  start.setToNow();  while (1)  {    robot.lock();    if (start.mSecSince() > 5000)    {      robot.unlock();      break;    }       robot.unlock();    ArUtil::sleep(50);  }  printf("directMotionExample: Telling the robot to move forwards one meter, then sleeping 5 seconds\n");  robot.lock();  robot.move(1000);  robot.unlock();  start.setToNow();  while (1)  {    robot.lock();    if (robot.isMoveDone())    {      printf("directMotionExample: Finished distance\n");      robot.unlock();      break;    }    if (start.mSecSince() > 5000)    {      printf("directMotionExample: Distance timed out\n");      robot.unlock();      break;    }       robot.unlock();    ArUtil::sleep(50);  }  printf("directMotionExample: Telling the robot to move backwards one meter, then sleeping 5 seconds\n");  robot.lock();  robot.move(-1000);  robot.unlock();  start.setToNow();  while (1)  {    robot.lock();    if (robot.isMoveDone())    {      printf("directMotionExample: Finished distance\n");      robot.unlock();      break;    }    if (start.mSecSince() > 10000)    {      printf("directMotionExample: Distance timed out\n");      robot.unlock();      break;    }    robot.unlock();    ArUtil::sleep(50);  }  printf("directMotionExample: Telling the robot to turn to 180, then sleeping 4 seconds\n");  robot.lock();  robot.setHeading(180);  robot.unlock();  start.setToNow();  while (1)  {    robot.lock();    if (robot.isHeadingDone(5))    {      printf("directMotionExample: Finished turn\n");      robot.unlock();      break;    }    if (start.mSecSince() > 5000)    {      printf("directMotionExample: Turn timed out\n");      robot.unlock();      break;    }    robot.unlock();    ArUtil::sleep(100);  }  printf("directMotionExample: Telling the robot to turn to 90, then sleeping 2 seconds\n");  robot.lock();  robot.setHeading(90);  robot.unlock();  start.setToNow();  while (1)  {    robot.lock();    if (robot.isHeadingDone(5))    {      printf("directMotionExample: Finished turn\n");      robot.unlock();      break;    }    if (start.mSecSince() > 5000)    {      printf("directMotionExample: turn timed out\n");      robot.unlock();      break;    }    robot.unlock();    ArUtil::sleep(100);  }  printf("directMotionExample: Setting vel2 to 200 mm/sec on both wheels, then sleeping 3 seconds\n");  robot.lock();  robot.setVel2(200, 200);  robot.unlock();  ArUtil::sleep(3000);  printf("directMotionExample: Stopping the robot, then sleeping for 2 seconds\n");  robot.lock();  robot.stop();  robot.unlock();  ArUtil::sleep(2000);  printf("directMotionExample: Setting velocity to 200 mm/sec then sleeping 3 seconds\n");  robot.lock();  robot.setVel(200);  robot.unlock();  ArUtil::sleep(3000);  printf("directMotionExample: Stopping the robot, then sleeping for 2 seconds\n");  robot.lock();  robot.stop();  robot.unlock();  ArUtil::sleep(2000);  printf("directMotionExample: Setting vel2 with 0 on left wheel, 200 mm/sec on right, then sleeping 5 seconds\n");  robot.lock();  robot.setVel2(0, 200);  robot.unlock();  ArUtil::sleep(5000);  printf("directMotionExample: Telling the robot to rotate at 50 deg/sec then sleeping 5 seconds\n");  robot.lock();  robot.setRotVel(50);  robot.unlock();  ArUtil::sleep(5000);  printf("directMotionExample: Telling the robot to rotate at -50 deg/sec then sleeping 5 seconds\n");  robot.lock();  robot.setRotVel(-50);  robot.unlock();  ArUtil::sleep(5000);  printf("directMotionExample: Setting vel2 with 0 on both wheels, then sleeping 3 seconds\n");  robot.lock();  robot.setVel2(0, 0);  robot.unlock();  ArUtil::sleep(3000);  printf("directMotionExample: Now having the robot change heading by -125 degrees, then sleeping for 6 seconds\n");  robot.lock();  robot.setDeltaHeading(-125);  robot.unlock();  ArUtil::sleep(6000);  printf("directMotionExample: Now having the robot change heading by 45 degrees, then sleeping for 6 seconds\n");  robot.lock();  robot.setDeltaHeading(45);  robot.unlock();  ArUtil::sleep(6000);  printf("directMotionExample: Setting vel2 with 200 on left wheel, 0 on right wheel, then sleeping 5 seconds\n");  robot.lock();  robot.setVel2(200, 0);  robot.unlock();  ArUtil::sleep(5000);  printf("directMotionExample: Done, exiting.\n");  Aria::exit(0);  return 0;}

这里写图片描述
Robot Callbacks

There are a number of useful callbacks invoked by ArRobot on connection events. You can add and remove them with the functions ArRobot::addConnectCB(), ArRobot::remConnectCB(), ArRobot::addFailedConnectCB(), ArRobot::remFailedConnectCB(), ArRobot::addDisconnectNormallyCB(), ArRobot::remDisconnectNormallyCB(), ArRobot::addDisconnectOnErrorCB(), ArRobot::remDisconnectOnErrorCB(), ArRobot::addRunExitCB(), ArRobot::remRunExitCB(). Read their individual documentation pages for details.

原创粉丝点击