admin管理员组文章数量:1516870
aria中的ArFunctor真相
以下内容写于2017-2018年,当时候对c++ functor, lambda , 可调用对象, 模板泛型,还不熟,所以把先锋机器人手册里关于ArFunctor 这块的内容全贴出来了。
真实的类型是函数对象,可以参考boost或者c++11函数对象部分.
以下部分是摘自aria开发文档中对这部分的介绍。
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 ArGloablFunctorArRetGlobalFunctor 含?个参数的函数指针
以上为抽象类,不可被实例化。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 thesecallbacks 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 andwill invoke the three functors. This is a typical use offunctors: to pass information or event notifications between looselycoupled 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 invokethe functor, but the return value is lost. (And is a possible sourceof 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");elseprintf("\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 inresponse to events such as the program connecting an disconnectingfrom the robot.
*/
//程序建立连接、连接失败、断链的“事件”时,被调用
**class ConnHandler**
{
public:// ConstructorConnHandler(ArRobot *robot);// Destructor, its just empty~ConnHandler(void) {}// to be called if the connection was madevoid connected(void);// to call if the connection failedvoid connFail(void);// to be called if the connection was lostvoid disconnected(void);
protected:// robot pointerArRobot *myRobot;// the functor callbacksArFunctorC<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 failed
void 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 connected
void 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 exit
void 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 aboveConnHandler 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.
以下链接来自boost程序库完全开发指南
本文标签: aria中的ArFunctor真相
版权声明:本文标题:aria中的ArFunctor真相 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.betaflare.com/biancheng/1731165900a1591582.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。


发表评论