[杂记]C++中的lambda函数、可变参数模板

323 阅读2分钟

这两个内容没有什么联系, 只是放到一起做一下笔记.


1. lambda函数

python中有lambda函数的用法:

list(map(lambda x: x**2, [1, 2, 3, 4]))

输出:

1, 4, 9, 16

lambda函数是对于表达式不太长的较简单的功能, 尽量缩短代码提高可读性的一种手段. 实际上C++里面也有. 如果从例子入手的话, 比如说, 我要对一个类进行自定义排序. 定义如下的牛马类, 对于一个数组的牛马, 将收入从小到大排. 对于收入相同的, 将年龄从大到小排:

class CowHorse{
private:
    std::string m_name; 
    int m_age;
    double m_salary;
public:
    CowHorse(const std::string& name, const int age, const double salary) : m_name(std::move(name)), m_age(age), m_salary(salary) {}
    bool operator<(CowHorse& ch);
    friend std::ostream& operator<<(std::ostream& os, CowHorse& ch);
};

方法一. 重载<运算符 因为sort函数默认是通过从小到大排序(std::less), 所以我们重载<运算符:

bool CowHorse::operator<(CowHorse& ch){
    if (this->m_salary != ch.m_salary)
        return this->m_salary < ch.m_salary;
    else 
        return this->m_age > ch.m_age;
}

运行

void func(){
    std::vector<CowHorse> arr;
    arr.push_back(CowHorse("amy", 35, 3000));
    arr.push_back(CowHorse("bob", 85, 3000));
    arr.push_back(CowHorse("damengzi", 45, 9000));
    arr.push_back(CowHorse("fool", 25, 1000));

    sort(arr.begin(), arr.end());

    for (auto& item: arr){
        std::cout << item;
    }

}

输出结果:

fool 25 1000
bob 85 3000
amy 35 3000
damengzi 45 9000

方法二. 仿函数 仿函数, 可以理解为函数对象, 即它可以是一个struct或class, 但用的时候当作函数来用, 为此需要重载()运算符. 定义自定义排序的类如下:

struct myCmp_{
    bool operator()(CowHorse& ch0, CowHorse& ch1){
        return ch0 < ch1;
    }
};

调用sort时, 第三个参数传入实例化的myCmp_类:

sort(arr.begin(), arr.end(), myCmp_());

结果也是正确的. 方法三. 函数指针 当然, 更简洁的方式是直接定义函数(因为这个例子比较简单):

bool myCmpFunc(CowHorse& ch0, CowHorse& ch1){
    return ch0 < ch1;
}

在调用sort时传入函数指针:

sort(arr.begin(), arr.end(), myCmpFunc);

方法四. lambda函数 lambda函数的格式为:

[返回值](参数){函数体}

或者

[](参数)->返回值类型{函数体}

因此可以这样写:

sort(arr.begin(), arr.end(), [&](CowHorse& ch0, CowHorse& ch1){return ch0 < ch1; });

其中[&]的意思是按引用接收. 在这里用不用这个都可以.

2. 可变参数模板

我们知道, python中有*args与**kwargs用于定义函数的可变参数.

>>> def test(**kwargs):
...     if 'name' in kwargs:
...         print(kwargs['name'])
...
>>> test(name='asds')

因此, 我们在不确定函数输入参数的时候, 可以这样来用, 并且加条件判断即可. 这样有助于泛化性. C++中也有这项功能, 只不过不如python这么强大(C++中的可变参数不是哈希表, 不能向上面那样索引)

例如, 我们要定义一个函数, 打印它所有的参数值:

void func() {return;}

template<typename T, typename... Args>  // Args是模板参数包, ...放前面
void func(T t, Args... args){  // 函数参数包作为函数参数
   std::cout << t;  // 打印第一项
   func(args...);  // 递归调用. 函数参数包后面跟省略号. 注意, 当args为空时, 由于func()未定义, 因此要重载一个func的版本.
}



int main(){
    std::string name = "ajsdqwq";
    func(name, name, name, name);

    system("pause");
    return 0;
}

输出:

ajsdqwqajsdqwqajsdqwqajsdqwq

其中, 模板参数包Args是一个类型的列表, 而函数参数包args是一个值的列表, 二者是一一对应的.