语法差异
- 普通 lambda 表达式:在定义时需要明确指定参数的具体类型。其基本语法为
[捕获列表](参数列表) -> 返回类型 { 函数体 }
,其中参数列表中的每个参数都要有明确的类型声明。
#include <iostream>
int main() {
auto add = [](int a, int b) {
return a + b;
};
std::cout << add(3, 5) << std::endl;
return 0;
}
在上述代码中,add
是一个普通 lambda 表达式,它明确指定了两个参数 a
和 b
的类型为 int
。
- 泛型 lambda 表达式:从 C++14 开始支持,使用
auto
关键字来声明参数类型,从而实现参数类型的泛化。其语法与普通 lambda 类似,但参数列表中使用auto
替代具体类型。
#include <iostream>
int main() {
auto genericAdd = [](auto a, auto b) {
return a + b;
};
std::cout << genericAdd(3, 5) << std::endl;
std::cout << genericAdd(3.5, 2.5) << std::endl;
return 0;
}
这里的 genericAdd
是一个泛型 lambda 表达式,auto
关键字让它可以接受不同类型的参数,既可以是整数,也可以是浮点数。
参数类型灵活性
- 普通 lambda 表达式:参数类型是固定的,在编译时就已经确定。这意味着它只能处理特定类型的参数,如果传入的参数类型与定义的类型不匹配,会导致编译错误。
#include <iostream>
int main() {
auto multiply = [](int a, int b) {
return a * b;
};
// 下面这行代码会编译错误,因为参数类型不匹配
// std::cout << multiply(3.5, 2.5) << std::endl;
return 0;
}
- 泛型 lambda 表达式:参数类型在调用时根据传入的实参自动推导,具有更高的灵活性。同一个泛型 lambda 可以处理多种不同类型的参数,只要这些参数支持 lambda 函数体中的操作。
#include <iostream>
#include <string>
int main() {
auto concatenate = [](auto a, auto b) {
return a + b;
};
std::cout << concatenate(3, 5) << std::endl;
std::cout << concatenate(std::string("Hello, "), std::string("World!")) << std::endl;
return 0;
}
在这个例子中,concatenate
泛型 lambda 既可以用于整数相加,也可以用于字符串拼接。
使用场景差异
- 普通 lambda 表达式:适用于处理特定类型数据的场景,当你明确知道函数需要处理的数据类型时,使用普通 lambda 可以提高代码的可读性和性能,因为编译器可以在编译时进行更精确的优化。例如,在对整数向量进行排序时,可以使用普通 lambda 来定义比较规则。
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> numbers = {5, 3, 8, 1, 2};
std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
return a < b;
});
for (int num : numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}
- 泛型 lambda 表达式:更适合于需要处理多种类型数据的通用算法或函数,能够提高代码的复用性。例如,在实现一个通用的打印函数时,使用泛型 lambda 可以打印不同类型的容器元素。
#include <iostream>
#include <vector>
#include <list>
template<typename Container>
void printContainer(const Container& container) {
auto printElement = [](const auto& element) {
std::cout << element << " ";
};
for (const auto& element : container) {
printElement(element);
}
std::cout << std::endl;
}
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
std::list<std::string> lst = {"apple", "banana", "cherry"};
printContainer(vec);
printContainer(lst);
return 0;
}
在上述代码中,printElement
泛型 lambda 可以用于打印不同类型容器中的元素,增强了代码的通用性。
实现原理差异
- 普通 lambda 表达式:编译器会为其生成一个具体的类类型,该类重载了函数调用运算符
operator()
,并且参数类型和返回类型都是明确的。 - 泛型 lambda 表达式:编译器同样会生成一个类类型,但该类的
operator()
是一个模板函数,参数类型由模板参数决定,在调用时根据实参进行模板实例化。
综上所述,泛型 lambda 表达式和普通 lambda 表达式各有优缺点,应根据具体的使用场景选择合适的 lambda 表达式类型。