首页 > 代码库 > 【C++】lambda函数介绍和个人理解

【C++】lambda函数介绍和个人理解

一般数据类型的别名

众所周知,在C++中,有一种不同于地址引用的值引用类型,也就是这种定义。

int  a = 10;
cout << a << endl;//:10
int& d = a;//d为a的别名
cout << d << endl;//:10
a++;
cout << a << endl;//:11
d++;
cout << a << endl;//:12
cout << d << endl;//:12

这种写法就相当于给一个整型数据单元a赋予了一个别名(alias)。就和人的大名和小名一样,名字不同,但是人相同。

那么能不能给函数也加一个别名呢?

函数别名的实现方法

我们看到,别名这种东西并不难实现,只要知道了函数的类型,就可以类似的写出别名的定义方式。但是这里就不得不提到函数指针这一小插曲。因为不论如何,我们都要先写出函数的类型。

比方说,我希望把获取最大最小值的那个函数max的函数类型写出来。

int max(int a, int b)
{
    return (a < b)? b: a;
}

不妨令这个函数的类型是dd2d(两个整型传入,一个整型传出),那么我们在写程序时需要这么做:

///函数max
int max(int a, int b){ return (a < b)? b: a; }
///typedef函数max的类型
typedef int (*dd2d)(int, int);
///写出max的别名函数
dd2d PickUpMaximum = max;

当然,一般的函数类型的模板类似于这个:

///函数fun声明或定义
return_type fun(var1_type, var2_type, var3_type, ...);
///typedef函数fun的类型
typedef return_type (*type_name)(var1_type, var2_type, var3_type, ...);
///新建变量并写出其别名
type_name fun_alias = fun;

如果你希望这个函数别名能够类似于数据一样可以通过一些操作什么的来改变函数内部的一些参数,嗯,这个功能目前实现不了,但是lambda函数实现了这一点。也就是通过初始化时的传入参数来调整函数内部的一些量。但是请注意,我们虽然成功的用一个别名调用了函数,但实质上我们只是调用了函数头指针,也就是通过这个地址来实现别名设置。所以不要想太多,这只是一个别名而已。

别名(alias)的优越性

其实我说的别名就是引用类型,只不过为了方便理解改称“别名”而已,而且加入了函数指针这一系统。

别名有什么好处呢?首先是具有一个很好的封装型。一般的别名都是一个“半const”类型。一旦一个变量名被声明为另一个变量名的别名,就不能够被声明称另一个变量的别名了。这就比方一对夫妇有两个小孩,老大叫“李华”,小的叫“李晓华”。如果老大的小名(也就是别名了)是“小华”,自然而然父母不会给小孩子再起这个“小华”的小名了。但为什么又是半const类型呢?因为这个别名所指向的内存和原变量名的地址一样,如果原变量是一个非const变量,自然这个别名也就可以修改自身的值。这个优点在封装,还有接口准备中作用非常好。不妨说我这里需要完成一个数据交换的过程(a与b交换),如果我们用别名来写函数接口,就会在使用过程中非常简单,省去很多麻烦。

///指针作为形参
void swap_pnt(int* a, int* b)
{
    int t;
    t = *a; *a = *b; *b = t;
}
///usage:
///    swap_pnt(&a, &b);

///别名作为形参
void swap_ref(int& a, int& b)
{
    int t;
    t = a; a = b; b = t;
}
///usage:
///    swap_ref(a, b);

其次,就是容错性。一般在大型工程中,为了防止函数重名,我们有时会利用命名空间的封装优势,或者就干脆直接把名字起的非常的冗长,以防止重名或者相似的名字。但是这样做也为我们的后续工作带来了很大的工作负担。简单的说,如果你在一个方法中,需要不停地调用一两个底层方法,那么就会出现一些非常非常非常冗长的代码,而且这些字符基本上是没有意义的,在项目的交流中虽然能够“见其名知其意”,但是总归是不满意。因而,可以利用这个函数别名来精简代码,保证可读性。简单的举个例子:

namespace Basic_Method
{
    //...
    struct TextBox{};
    //...
    string getStringFromTextBox(TextBox& );
    string getCountNumberFromTextBox(TextBox& );
    double getAverage(int[] , int );
    //...
}

namespace Interface_of_Rate
{
    //...
    typedef Basic_Method::TextBox TextBox;
    void newInterface(TextBox& , time_t );
    void flash(TextBox& , time_t );
    void getUpdate(TextBox& , time_t );
    //...
}

void Interface_of_Rate::getUpdate(TextBox id, time_t ti)
{
    ///typedef function
    typedef string (*getStr)(TextBox);
    getStr getnote = Basic_Method::getStringFromTextBox;
    getStr getcnts = Basic_Method::getCountNumberFromTextBox;
    ///直接使用
    string note = getnote(id);
    string cnts = getcnts(id);
    
    //...
}

当然其实也可以用局部的#define来完成类似的过程,但是一般来说是不推荐的,毕竟#define是一个很危险的使用方法,很危险。

关于别名就这么多吧,大概用处也就那点,不难学。