假设相同的 lambda 表达式具有不同的类型是否安全?
Is it safe to assume that identical lambda expressions have different types?
我正在试验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
,即a
和b
当然是同一类型,c
具有不同的类型。
编译器是否允许c
与a
属于同一类型?
我的意思是表达式是相同的,这将是一个明显的优化。
PS:如果捕获阻止了这种优化,那么没有捕获的 lambda 呢?
相关:C++11/1Y lambda 函数的类型签名是什么?以及 lambda 表达式的"类型"可以表达吗?
编译器
是否允许
c
与a
属于同一类型?
不。[&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
您可以看到有两个函数模板实例化。
相关文章:
- 检查 std::shared_ptr<> 的当前底层类型是否为 T
- 检查函数返回类型是否与STL容器类型值相同
- 检查某些类型是否是模板类 std::optional 的实例化
- 表达式 SFINAE:如何根据类型是否包含具有一个或多个参数的函数来选择模板版本
- 检查一个类型是否直接派生自"enable if"上下文中的另一个类型(是其子类型)
- 如何检查模板类型是否可以从给定类型构造
- 用于检测函数类型是否为否的特征
- 了解类型是否可调用
- 通过引用传递参数;函数返回类型是否必须为 VOID?
- 键入特征以检查类型是否可从流和 MSVC 读取
- 从双精度转换为整数的显式类型是否始终检查整数溢出?
- 如何获取类型是否真正可移动可构造
- 在编译时检查类型是否为 std::basic_string<T> C++
- 在C++中,转换为simd类型是否有未定义的行为
- POD类型是否完全等同于琐碎的标准布局类型
- 聚合类型是否意味着它也是标准布局
- 有没有一种方法可以使用SFINAE来检测一个类型是否实现了给定的抽象基类
- 验证(使用 static_assert)元组类型是否遵循某种顺序(有状态编译时检查)
- 强制转换为不相关的引用类型是否违反严格的别名规则?
- 特征:从数组类型中获取标量类型是否记录?