假设相同的 lambda 表达式具有不同的类型是否安全?

Is it safe to assume that identical lambda expressions have different types?

本文关键字:类型 是否 安全 lambda 表达式 假设      更新时间:2023-10-16

我正在试验lambdas以及不同的lambda表达式具有不同类型的事实,即使它们是相同的。考虑此代码

#include <iostream>
template <typename T> void once(T t){
static bool first_call = true;
if (first_call) t();
first_call = false;
}
int main() {    
int counter = 0;
auto a = [&counter](){counter++;};
once(a);
once(a);
std::cout << counter;              // 1
auto b = a;                        // same type
once(b);
std::cout << counter;              // 1
auto c = [&counter](){counter++;}; // different type
once(c);
once(c);               
std::cout << counter;              // 2
}

这打印112,即ab当然是同一类型,c具有不同的类型。

编译器是否允许ca属于同一类型?

我的意思是表达式是相同的,这将是一个明显的优化。

PS:如果捕获阻止了这种优化,那么没有捕获的 lambda 呢?

相关:C++11/1Y lambda 函数的类型签名是什么?以及 lambda 表达式的"类型"可以表达吗?

编译器

是否允许ca属于同一类型?

不。[&counter](){counter++;}是一个 lambda 表达式,根据 [expr.prim.lambda.closure]/1:

lambda 表达式的类型(也是闭包对象的类型(是一种唯一的、未命名的非联合类类型,称为闭包类型,其属性如下所述。

因此,对于每个 lambda 表达式,即使它与前一个表达式相同,您也会得到一个唯一的类型。

您可以使用typeid来检查是否属于这种情况,如下所示:

#include <iostream>
#include <typeinfo>
template <typename T> void once(T t){
static bool first_call = true;
std::cout << typeid(t).name() << std::endl;
if (first_call) {
t();
}
first_call = false;
}
int main() {    
int counter = 0;
auto a = [&counter](){counter++;};
once(a);
once(a);
std::cout << counter << std::endl; // 1
auto b = a;                        // same type
once(b);
std::cout << counter << std::endl; // 1
auto c = [&counter](){counter++;}; // different type
once(c);
once(c);               
std::cout << counter << std::endl; // 2
}

结果:

Z4mainEUlvE_                                                                                                          
Z4mainEUlvE_                                                                                                          
1                                                                                                                     
Z4mainEUlvE_                                                                                                          
1                                                                                                                     
Z4mainEUlvE0_                                                                                                         
Z4mainEUlvE0_                                                                                                         
2

您可以看到有两个函数模板实例化。