某企业面试题:lambda 表达式的类型是什么? 没有任何参数索引的两个lambda 表达式类型相同吗?

1. Lambda表达式的类型是什么?

Lambda表达式的类型是一个唯一的、未命名的(匿名的)闭包类型,由编译器在编译时自动生成。

这意味着:

  • 没有明确的类型名:你无法在代码中直接用typename来声明一个Lambda的类型(例如 MyLambdaType lambda = []{}; 是不行的)。
  • 编译器生成:每个Lambda表达式都会导致编译器生成一个全新的、独一无二的类类型。这个生成的类重载了函数调用运算符operator(),并且可能包含一些成员变量来存储捕获的变量。
  • 类似于函子(Functor):你可以把它理解为一个编译器自动为你生成的、匿名的函数对象(仿函数)类。

如何存储和传递Lambda?
正因为其类型是匿名且唯一的,我们通常使用以下方式来处理它:

  1. 使用 auto(最常用、最推荐):

    auto myLambda = [] { std::cout << "Hello Lambda"; };
    // myLambda 的类型就是那个编译器生成的唯一类型
    
  2. 使用 std::function(包装器,有微小性能开销,但更灵活):
    std::function 是一个多态的函数包装器,它可以包装任何调用签名兼容的可调用对象(如函数指针、Lambda、仿函数)。

    #include <functional>
    
    std::function<void()> myFunction = [] { std::cout << "Hello"; };
    // 这里,不同类型的Lambda只要签名是 `void()`,都可以被赋值给这个 `std::function`
    

2. 两个没有任何参数且代码相同的Lambda表达式,类型相同吗?

绝对不相同。

这是一个非常关键的特性。即使两个Lambda表达式在代码上看完全一模一样(相同的捕获列表、相同的参数列表、相同的函数体),编译器也会为它们分别生成两个不同的、独立的匿名类型。

你可以把它想象成编译器为你写了两个不同的类,虽然这两个类的实现完全一样,但它们的类名是不同的。

示例证明:

#include <iostream>
#include <type_traits>

int main() {
    auto lambda1 = []() { std::cout << "Hello"; };
    auto lambda2 = []() { std::cout << "Hello"; }; // 与lambda1完全相同

    // 检查类型是否相同
    if (std::is_same_v<decltype(lambda1), decltype(lambda2)>) {
        std::cout << "Types are the same.\n";
    } else {
        std::cout << "Types are NOT the same.\n"; // 这行会被执行
    }

    // 每个Lambda的大小可能也不同(取决于捕获的内容),
    // 但在这个例子中,它们都没捕获任何东西,所以大小通常相同。
    std::cout << "Size of lambda1: " << sizeof(lambda1) << std::endl; // 通常是 1
    std::cout << "Size of lambda2: " << sizeof(lambda2) << std::endl; // 通常是 1

    return 0;
}

输出结果必然是:

Types are NOT the same.
Size of lambda1: 1
Size of lambda2: 1

为什么设计成这样?
这种“每个Lambda类型唯一”的设计提供了极大的灵活性和安全性。编译器可以为每个Lambda进行完全独立的、最优化的代码生成,而不用担心不同Lambda之间的类型冲突。

特例:拷贝
但是,同一个Lambda表达式的拷贝,其类型当然是相同的。

auto lambda1 = []() {};
auto lambda1_copy = lambda1; // lambda1_copy 的类型和 lambda1 完全相同

// 这个检查会通过
static_assert(std::is_same_v<decltype(lambda1), decltype(lambda1_copy)>);

总结

特性 说明
Lambda类型 唯一的、匿名的编译器生成类型。
相同代码的Lambda 类型不同。每个Lambda表达式都会生成一个新类型。
Lambda的拷贝 类型相同。
存储方式 使用 autostd::function
Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐