在controller.cpp中有这样一块代码:
typedef struct _Controller{ const char *test_name; std::function<TestScene*()> callback; } Controller;
Controller g_aTestNames[] = { // // TESTS MUST BE ORDERED ALPHABETICALLY // violators will be prosecuted // { "Accelerometer", []() { return new AccelerometerTestScene(); } }, { "ActionManager", [](){return new ActionManagerTestScene(); } }, { "Actions - Basic", [](){ return new ActionsTestScene(); } }, { "Actions - Ease", [](){return new ActionsEaseTestScene();} }, { "Actions - Progress", [](){return new ProgressActionsTestScene(); } }, { "Audio - CocosDenshion", []() { return new CocosDenshionTestScene(); } }, { "Box2d - Basic", []() { return new Box2DTestScene(); } }, { "Box2d - TestBed", []() { return new Box2dTestBedScene(); } }, { "Bugs", []() { return new BugsTestScene(); } }, { "Chipmunk", []() { return new ChipmunkAccelTouchTestScene(); } }, { "Click and Move", [](){return new ClickAndMoveTestScene(); } }, { "Configuration", []() { return new ConfigurationTestScene(); } }, #if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT) { "Console", []() { return new ConsoleTestScene(); } }, #endif #if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT) #if (CC_TARGET_PLATFORM != CC_PLATFORM_EMSCRIPTEN) #if (CC_TARGET_PLATFORM != CC_PLATFORM_NACL) #if (CC_TARGET_PLATFORM != CC_PLATFORM_MARMALADE) #if (CC_TARGET_PLATFORM != CC_PLATFORM_BADA) { "Curl", []() { return new CurlTestScene(); } }, #endif #endif #endif #endif #endif { "Current Language", []() { return new CurrentLanguageTestScene(); } }, { "EventDispatcher", []() { return new EventDispatcherTestScene(); } }, { "Effects - Advanced", []() { return new EffectAdvanceScene(); } }, { "Effects - Basic", [](){return new EffectTestScene();} }, { "Extensions", []() { return new ExtensionsTestScene(); } }, { "FileUtils", []() { return new FileUtilsTestScene(); } }, { "Fonts", []() { return new FontTestScene(); } }, { "Interval", [](){return new IntervalTestScene(); } }, { "Keyboard", []() { return new KeyboardTestScene(); } }, { "Keypad", []() { return new KeypadTestScene(); } }, { "Node: Clipping", []() { return new ClippingNodeTestScene(); } }, { "Node: Draw", [](){return new DrawPrimitivesTestScene();} }, { "Node: Label - New API", [](){return new AtlasTestSceneNew(); } }, { "Node: Label - Old API", [](){return new AtlasTestScene(); } }, { "Node: Layer", [](){return new LayerTestScene();} }, { "Node: Menu", [](){return new MenuTestScene();} }, { "Node: MotionStreak", [](){return new MotionStreakTestScene();} }, { "Node: Node", [](){return new CocosNodeTestScene();} }, { "Node: Parallax", [](){return new ParallaxTestScene(); } }, { "Node: Particles", [](){return new ParticleTestScene(); } }, { "Node: Physics", []() { return new PhysicsTestScene(); } }, { "Node: RenderTexture", [](){return new RenderTextureScene(); } }, { "Node: Scene", [](){return new SceneTestScene();} }, { "Node: Spine", []() { return new SpineTestScene(); } }, { "Node: Sprite", [](){return new SpriteTestScene(); } }, { "Node: Sprite3D", [](){ return new Sprite3DTestScene(); }}, { "Node: TileMap", [](){return new TileMapTestScene(); } }, { "Node: Text Input", [](){return new TextInputTestScene(); } }, { "Node: UI", [](){ return new UITestScene(); }}, { "Mouse", []() { return new MouseTestScene(); } }, { "MutiTouch", []() { return new MutiTouchTestScene(); } }, { "Performance tests", []() { return new PerformanceTestScene(); } }, { "Renderer", []() { return new NewRendererTestScene(); } }, { "ReleasePool", [](){ return new ReleasePoolTestScene(); } }, { "Rotate World", [](){return new RotateWorldTestScene(); } }, { "Scheduler", [](){return new SchedulerTestScene(); } }, { "Shader - Basic", []() { return new ShaderTestScene(); } }, { "Shader - Sprite", []() { return new ShaderTestScene2(); } }, { "Texture2D", [](){return new TextureTestScene(); } }, { "TextureCache", []() { return new TextureCacheTestScene(); } }, { "TexturePacker Encryption", []() { return new TextureAtlasEncryptionTestScene(); } }, { "Touches", [](){return new PongScene();} }, { "Transitions", [](){return new TransitionsTestScene();} }, { "Unit Test", []() { return new UnitTestScene(); }}, { "UserDefault", []() { return new UserDefaultTestScene(); } }, { "Zwoptex", []() { return new ZwoptexTestScene(); } }, };
这里用到了function和lambda表达式
function是一组函数对象包装类的模板,实现了一个泛型的回调机制。function与函数指针比较相似,优点在于它允许用户在目标的实现上拥有更大的弹性,即目标既可以是普通函数,也可以是函数对象和类的成员函数,而且可以给函数添加状态。
声明一个function时,需要给出所包装的函数对象的返回值类型和各个参数的类型。比如,声明一个function,它返回一个bool类型并接受一个int类型和一个float类型的参数,可以像下面这样:
function<bool (int, float)> f;
下面简要介绍一下function的比较重要的几个接口。
function();
缺省构造函数,创建一个空的函数对象。如果一个空的function被调用,将会抛出一个类型为bad_function_call的异常。
template <typename F> function(F g);
这个泛型的构造函数接受一个兼容的函数对象,即这样一个函数或函数对象,它的返回类型与被构造的function的返回类型或者一样,或者可以隐式转换, 并且它的参数也要与被构造的function的参数类型或者一样,或者可以隐式转换。注意,也可以使用另外一个function实例来进行构造。这样做, 并且function g为空,则被构造的function也为空。使用空的函数指针和空的成员函数指针也会产生空的function。如果这样做,并且function g为空,则被构造的function也为空。使用空的函数指针和空的成员函数指针也会产生空的function。
template <typename F> function(reference_wrapper<F> g);
这个构造函数与前一个类似,但它接受的函数对象包装在一个reference_wrapper中,用以避免通过值来传递而产生函数或函数对象的一份拷贝。这同样要求函数对象兼容于function的签名。
function& operator=(const function& g);
赋值操作符保存g中的函数或函数对象的一份拷贝;如果g为空,被赋值的函数也将为空。
template<typename F> function& operator=(F g);
这个泛型赋值操作符接受一个兼容的函数指针或函数对象。注意,也可以用另一个 function 实例(带有不同但兼容的签名)来赋值。这同样意味着,如果g是另一个function实例且为空,则赋值后的函数也为空。赋值一个空的函数指针或空的成员 函数指针也会使function为空。
bool empty() const;
这个成员函数返回一个布尔值,表示该function是否含有一个函数或函数对象。如果有一个目标函数或函数对象可被调用,它返回 false 。因为一个function可以在一个布尔上下文中测试,或者与0进行比较,因此这个成员函数可能会在未来版本的库中被取消,你应该避免使用它。
void clear();
这个成员函数清除 function, 即它不再关联到一个函数或函数对象。如果function已经是空的,这个调用没有影响。在调用后,function肯定为空。令一个function为空的首选方法是赋0给它;clear 可能在未来版本的库中被取消。
result_type operator()(Arg1 a1, Arg2 a2, ..., ArgN aN) const;
调用操作符是调用function的方法。你不能调用一个空的 function ,那样会抛出一个bad_function_call的异常。调用操作符的执行会调用function中的函数或函数对象,并返回它的结果。
下面分别给出使用function来包装普通函数,函数对象和类的成员函数的参考代码。
1、普通函数
1 int Add(int x, int y)2 3 {4 return x+y;5 }6 function<int (int,int)> f = Add;7 int z = f(2, 3);
2、函数对象
1 class CStudent 2 { 3 public: 4 void operator() (string strName, int nAge) 5 { 6 cout << strName << " : " << nAge << endl; 7 } 8 }; 9 10 CStudent stu;11 function<void (string, int)> f = stu;12 f("Mike", 12);
3、类的成员函数
1 struct TAdd 2 { 3 int Add(int x,int y) 4 { 5 return x+y; 6 } 7 }; 8 9 function<int (TAdd *, int, int)> f = TAdd::Add;10 TAdd tAdd;11 f(&tAdd, 2, 3); // 如果前面的模板参数为传值或引用,直接传入tAdd即可
接下来我们来看看使用function来保存函数对象状态的情况。考虑下面的代码:
1 class CAdd 2 { 3 public: 4 CAdd():m_nSum(0) { NULL; } 5 int operator()(int i) 6 { 7 m_nSum += i; 8 return m_nSum; 9 }10 11 int Sum() const 12 {13 return m_nSum;14 }15 16 private:17 int m_nSum;18 };19 20 int main() 21 {22 CAdd add;23 function<int (int)> f1 = add;24 function<int (int)> f2 = add;25 cout << f1(10) << "," << f2(10) << "," << add.Sum() << endl;26 return 0;27 }
可能和大家想象的结果不一样,上面程序的输出是:10,10,0。我们将同一个函数对象赋值给了两个function,然后分别调用了这两个 function,但函数对象中m_nSum的状态并没有被保持,问题出在哪儿呢?这是因为function的缺省行为是拷贝一份传递给它的函数对象,于 是f1和f2中保存的都是add对象的拷贝,调用f1和f2后,add对象中的值并没有被修改。
C++ 11中提供了ref和cref函数,来提供对象的引用和常引用的包装。要使function能够正确地保存函数对象的状态,我们可以这样来修改代码:
1 CAdd add;2 function<int(int)> f1 = ref(add);3 function<int(int)> f2 = ref(add);
另外,在两个function之间赋值时,如果源function保存的是函数对象的拷贝,则目标function保存的也是函数对象的拷贝;如果源function保存的是函数对象的引用,则目标function保存的也是函数对象的引用
lambda本质上就是一个函数指针。
C++11引入了lambda表达式,使得程序员可以定义匿名函数,该函数是一次性执行的,既方便了编程,又能防止别人的访问。
Lambda表达式的语法通过下图来介绍:
这里假设我们定义了一个如上图的lambda表达式。现在来介绍途中标有编号的各个部分是什么意思。
Lambda表达式的引入标志,在‘[]’里面可以填入‘=’或‘&’表示该lambda表达式“捕获”(lambda表达式在一定的 scope可以访问的数据)的数据时以什么方式捕获的,‘&’表示一引用的方式;‘=’表明以值传递的方式捕获,除非专门指出。
Lambda表达式的参数列表
Mutable 标识
异常标识
返回值
“函数”体,也就是lambda表达式需要进行的实际操作
将上图的代码片段补充完整:
int x = 10;
int y = 3;
int z ;
z = [=]()mutable throw() -> int { int n = x + y; x = y ; y = n; return n;}();
cout<<z<<endl;
cout<<"x:"<<x<<"\t"<<"y:"<<y<<endl;
运行结果为:
13
x: 10 y: 3
因为是以值传递的方式访问x,y所以x,y的值并没有发生改变
现在我们队lambda表达式的基本语法已经有一些了解,下面来举几个例子。
首先这个例子说明如何向lambda表达式里面传递参数:
#include <iostream>
using namespace std;
int main()
{
int n = [] (int x, int y) { return x + y; }(5, 4);
cout << n << endl;
}
运行结果为:9
通过这个例子我们可以看出,通过“函数体”后面的‘()’传入参数。
接下来这个例子可以看出,可以像调用函数一样使用lambda表达式,但是感觉这种方式和普通函数的定义与调用就差不多了,这里只是学习使用方式而已。
#include <iostream>
using namespace std;
int main()
{
auto f = [] (int x, int y) { return x + y; };
cout << f(21, 12) << endl;
}
运行结果为:33
Lambda表达式与STL算法一起使用,自己写测试代码的时候经常用到排序、输出数组什么的,通过下面列举的几个算法也比较方便:
#include <iostream>
#include <algorithm>
#include <ctime>
using namespace std;
int main()
{
int a[10] = {0};
srand(time(NULL));
generate(a,a+10,[]()->int { return rand() % 100; });
cout<<"before sort: "<<endl;
for_each(a, a+10, [&](int i){ cout<< i <<" "; });
cout<<endl;
cout<<"After sort"<<endl;
sort(a,a+10);
for_each(a, a+10, [&](int i){ cout<< i <<" "; });
return 0;
}
Lambda表达式的嵌套:
#include <iostream>
int main()
{
using namespace std;
int m = [](int x)
{ return [](int y) { return y * 2; }(x) + 3; }(5);
cout << m << endl;
}
运行结果:13
以上代码在VC10和VC11上都能顺利编译通过。感觉lambda表达式还是比较有意思的语法,也是我接触的第一个VC11扩展。