天天看點

C++|從函數對象到lambda表達式以及操作參數化

作者:小智雅彙

函數對象(function object)是指一個類重載函數運算符"()"後,使用類變量調用函數運算符時,其行為類似函數調用,是以也稱為仿函數(functor)。

lambda表達式是函數對象的文法糖,使用三種括号來定義:

[](){};           

[]内可以是空白,表示不捕獲任何lambda表達式外部的任何變量,其内也可以聲明需要捕獲的lambda表達式外部的變量,可以是值捕獲,也可以是引用捕獲。

()内用于定義lambda表達式的參數;

{}内用于定義語句體,相當于函數的函數體。

lambda表達式直接調用的文法形式:

[](){}(); // 第二對小括号()表達式表示調用,内部的值對應第一對小括号()内聲明的參數。           

操作參數化是指用函數指針、函數對象或lambda表達式做函數參數。

lambda表達式這種文法形式的引入主要用于操作參數化。

1 成員函數與函數對象

成員函數:

#include <iostream>
class AddNum{
public:
    AddNum(int num):num_(num){}
    int addNum(int x)const{
        return num_+x;
    }
private:
    int num_;
};

int main() {
    auto add_num = AddNum(10);
    auto x = add_num.addNum(5);
    std::cout<<"x:"<<x<<std::endl;
    return 0;
}           

将成員函數改寫為函數對象的形式:

#include <iostream>
class AddNum{
public:
    AddNum(int num):num_(num){}
    int operator()(int x)const{
        return num_+x;
    }
private:
    int num_;
};

int main() {
    auto add_num = AddNum(10);
    auto x = add_num(5);
    std::cout<<"x:"<<x<<std::endl;
    return 0;
}           

2 從函數對象到lambda表達式

lambda表達式:

#include <iostream>
int main() {
    auto x = [num=10](int x){return num + x;}(5);
    std::cout<<"x:"<<x<<std::endl;
    return 0;
}           

lambda表達式是函數對象的文法糖。

也可以對lambda表達式進行命名,命名後可以如同函數一樣調用:

#include <iostream>
int main() {
    auto add_num = [num=10](int x){return num + x;};
    auto x = add_num(5);
    std::cout<<"x:"<<x<<std::endl;
    return 0;
}           

auto推導的lambda表達式類型相當于以下類型:

#include <iostream>
#include <functional>
int main() {
    std::function<int(int)> add_num = [num=10](int x){return num + x;};
    auto x = add_num(5);
    std::cout<<"x:"<<x<<std::endl;
    return 0;
}           

3 操作參數化

操作參數化也就是用函數指針、函數對象或lambda表達式做函數參數。

如for_each()函數:

template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function fn)
{
    while(first!=last) {
        fn (*first); // fn是for_each的參數,first也是,同時也是fn的參數
        ++first;
    }
    return fn;      // or, since C++11: return move(fn);
}           

3.1 使用函數指針讓操作參數化

#include <iostream>
#include <vector>
#include <algorithm>
void print_int(int x){
	std::cout<<"x: "<<x<<std::endl;
}
int main() {
    std::vector<int> arr = {1,3,5,7,9};
    std::for_each(arr.begin(),arr.end(),print_int);
    return 0;
}           

3.2 使用函數對象讓操作參數化

#include <iostream>
#include <vector>
#include <algorithm>
struct print_int{
	void operator()(int x){
	    std::cout<<"x: "<<x<<std::endl;
	}
};
int main() {
    std::vector<int> arr = {1,3,5,7,9};
    std::for_each(arr.begin(),arr.end(),print_int());
    return 0;
}           

3.3 使用lambda表達式讓操作參數化

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> arr = {1,3,5,7,9};
    std::for_each(arr.begin(),arr.end(),[](int x){std::cout<<"x: "<<x<<std::endl;});
    return 0;
}           

4 lambda表達式還可以捕獲表達式外部的變量

4.1 按值捕獲

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
	int times = 2;
	int others = 3;
    std::vector<int> arr = {1,3,5,7,9};
    std::for_each(arr.begin(),arr.end(),[times](int x){std::cout<<"x: "<<x*times<<std::endl;}); // 按值捕獲times
    return 0;
}           

也可以全部按值捕獲:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
	int times = 2;
	int others = 3;
    std::vector<int> arr = {1,3,5,7,9};
    std::for_each(arr.begin(),arr.end(),[=](int x){std::cout<<"x: "<<x*times*others<<std::endl;}); // [=]表示全部按值捕獲
    return 0;
}           

4.2 按引用捕獲

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
	int times = 2;
	int others = 3;
    std::vector<int> arr = {1,3,5,7,9};
    std::for_each(arr.begin(),arr.end(),[×](int x){std::cout<<"x: "<<x*++times<<std::endl;}); // [×]表示按引用捕獲times
    return 0;
}           

也可以全部按引用捕獲:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
	int times = 2;
	int others = 3;
    std::vector<int> arr = {1,3,5,7,9};
    std::for_each(arr.begin(),arr.end(),[&](int x){std::cout<<"x: "<<x*++times*++others<<std::endl;}); // [&]表示全部引用
    return 0;
}           

ref

https://www.bilibili.com/video/BV1oW4y1z7nq

https://www.bilibili.com/video/BV1CD4y1y73q

-End-