lambdas和等式/不等式算子
lambdas and equality/inequality operator
我有一个关于lambdas的等式比较的问题。我试着阅读了一些参考资料,但没有发现任何关于这方面的信息。
[] (Args ...args) -> ReturnType { ... };
对于这种类型的lambda,它们实际上不是闭包,因为它们有空的捕获列表,运算符==
和!=
的工作方式与静态函数的工作方式相同(看起来,编译器也将它们生成为静态函数)。但对于闭包,任何以相同方式进行比较的尝试都会导致编译错误。
下面是一个简单的程序,例如:
#include <typeinfo>
#include <iostream>
struct WrapperBase {
virtual ~WrapperBase() = default;
virtual bool operator==(WrapperBase& v) = 0;
virtual bool operator!=(WrapperBase& v) = 0;
};
template<typename _Tp>
struct Wrapper : WrapperBase {
Wrapper(const _Tp& v) : value(v) { }
bool operator==(WrapperBase& v) override {
try {
Wrapper<_Tp>& vv = dynamic_cast<Wrapper<_Tp>&>(v);
return value == vv.value;
}
catch(std::bad_cast& err) { }
return false;
}
bool operator!=(WrapperBase& v) override {
try {
Wrapper<_Tp>& vv = dynamic_cast<Wrapper<_Tp>&>(v);
return value != vv.value;
}
catch(std::bad_cast& err) { }
return true;
}
//
_Tp value;
};
template<typename _Tp>
WrapperBase* create_wrapper(const _Tp& v) {
return new Wrapper<_Tp>(v);
}
struct Base {
Base(int a, int b) : wrapper(nullptr), a(a), b(b) { }
virtual ~Base() { delete wrapper; }
virtual WrapperBase* create_wrapper() = 0;
WrapperBase* wrapper;
int a;
int b;
};
struct ClassA : Base {
ClassA(int a, int b) : Base(a, b) {
wrapper = create_wrapper();
}
WrapperBase* create_wrapper() override {
auto lambda = [] (int v1, int v2) { return v1 + v2; };
return ::create_wrapper(lambda);
}
};
struct ClassB : Base {
ClassB(int a, int b) : Base(a, b) {
wrapper = create_wrapper();
}
WrapperBase* create_wrapper() override {
auto lambda = [=] (int v1, int v2) { return a + b + v1 + v2; };
return ::create_wrapper(lambda);
}
};
int main(int argc, char** argv) {
std::cout << std::boolalpha;
// all works fine:
ClassA a1(1, 2);
ClassA a2(3, 4);
std::cout << (*a1.wrapper == *a1.wrapper) << std::endl; // true
std::cout << (*a2.wrapper == *a2.wrapper) << std::endl; // true
std::cout << (*a1.wrapper == *a2.wrapper) << std::endl; // true
// cause compilation error:
ClassB b1(1, 2);
ClassB b2(3, 4);
std::cout << (*b1.wrapper == *b1.wrapper) << std::endl;
std::cout << (*b2.wrapper == *b2.wrapper) << std::endl;
std::cout << (*b1.wrapper == *b2.wrapper) << std::endl;
return 0;
}
比较在ClassA实例中创建的lambda总是返回true
,即使它们是在不同的上下文中创建的(正如我所说)。另一方面,ClassB甚至不编译,因为找不到其lambda的运算符==
和!=
。
这个程序的形式似乎不太好,以我尝试的方式比较lambdas会导致程序的行为不明确。但是,如果这真的是未定义的行为,如何将它们进行比较?(我想,没关系)
对于这种类型的lambda,它们实际上不是闭包,因为它们捕获列表为空,运算符==和!=工作方式与对于静态函数(看起来,编译器将它们生成为静态函数)。
它之所以有效,是因为没有捕获的lambda的闭包类型提供了一个返回函数指针的转换运算符。这些是可比较的。[expr.prim.lambda]/6(强调矿):
没有lambda捕获的lambda表达式的闭包类型有一个公共的非虚拟的非显式的常量转换函数指向与闭包类型的函数调用运算符。此返回的值转换函数应为函数的地址,当已调用,其效果与调用闭包类型的函数相同呼叫接线员。
(如果转换运算符是显式的,则比较将不起作用)
大致来说,[] {}
形式的lambda转换为
struct closure_type
{
private:
static void call() {}
public:
// closure_type() = delete; // Commented for the sake of the demo
closure_type& operator=(closure_type const&) = delete;
void operator()() const { /*return call();*/ }
operator decltype(&call)() const
{
return &call;
}
};
正如您可能已经注意到的,转换运算符每次都返回相同的函数指针。尽管如果发生类似的情况会非常令人惊讶,但该标准确实允许为同一闭包对象的转换运算符调用返回不同的函数指针;因此,两个闭包对象的比较具有实现定义的值。(不过,在所有实现中,对于相同类型的两个闭包对象,它应该是true
。)
- 为什么在C++20中对lambdas使用"std::bind_front"
- 查找不等式为真的次数时出现问题
- C++中 c_str() 和字符* 的不等式
- 查找满足浮点不等式方程的最小整数
- JavaScript箭头函数:我们能否像C ++ lambdas一样捕获值
- 为什么以下不等式在C++计算为真?
- 使用lambdas初始化多维数组
- C++17中没有自动参数的模板lambdas
- 通过引用捕获与移动,lambdas
- 我可以使用匿名lambdas坚持静态值
- lambdas的可继承性是否由标准保证
- C ;使用lambdas在类中有条件地扩展功能(MWE的SEG故障)
- 在具有功能的C++中嵌套无捕获的lambdas?
- Templated Variables Bug With Lambdas in Visual Studio?
- C 使用多个lambdas/绑定以引用相同的功能
- 直接将lambdas传递到函数
- 使QTConcurrent ::映射与Lambdas一起工作
- C 中的枚举和lambdas的地图
- STD ::仅移动的Lambdas的向量是可能的
- lambdas和等式/不等式算子