Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ lambdas与等式/不等式算子_C++_C++11_Lambda_Closures - Fatal编程技术网

C++ lambdas与等式/不等式算子

C++ lambdas与等式/不等式算子,c++,c++11,lambda,closures,C++,C++11,Lambda,Closures,我有一个关于lambdas的等式比较的问题。 我试着阅读了一些参考资料,但没有发现任何有关这方面的信息 [] (Args ...args) -> ReturnType { ... }; 对于这种类型的lambda,它们实际上不是闭包,因为它们有空的捕获列表,操作符=和=的工作方式与静态函数相同(看起来,编译器也会将它们生成为静态函数)。但对于闭包,任何以相同方式进行比较的尝试都会导致编译错误 下面是一些简单的程序,例如: #include <typeinfo> #includ

我有一个关于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;
}
#包括
#包括
结构包装器库{
virtual~WrapperBase()=默认值;
虚拟布尔运算符==(WrapperBase&v)=0;
虚拟布尔运算符!=(WrapperBase&v)=0;
};
模板
结构包装器:包装器库{
包装器(const_Tp&v):值(v){
布尔运算符==(WrapperBase&v)覆盖{
试一试{
包装&vv=动态_铸造(v);
返回值==vv.value;
}
catch(std::bad_cast&err){
返回false;
}
布尔运算符!=(WrapperBase&v)覆盖{
试一试{
包装&vv=动态_铸造(v);
返回值!=vv.value;
}
catch(std::bad_cast&err){
返回true;
}
//
_Tp值;
};
模板
WrapperBase*创建包装器(const\u Tp&v){
返回新包装(v);
}
结构基{
Base(inta,intb):包装器(nullptr),a(a),b(b){
virtual~Base(){delete wrapper;}
虚拟包装器库*create_wrapper()=0;
包装器基*包装器;
INTA;
int b;
};
结构类A:基{
类别a(内部a,内部b):基础(内部a,内部b){
包装器=创建包装器();
}
WrapperBase*创建_wrapper()覆盖{
自动lambda=[](intv1,intv2){返回v1+v2;};
return::创建_包装(lambda);
}
};
结构类B:基{
类b(intA,intB):基(a,b){
包装器=创建包装器();
}
WrapperBase*创建_wrapper()覆盖{
自动lambda=[=](intv1,intv2){返回a+b+v1+v2;};
return::创建_包装(lambda);
}
};
int main(int argc,字符**argv){
标准::cout
对于这种类型的lambda,它们实际上不是闭包,因为它们
如果捕获列表为空,则运算符==和!=的工作方式与
对于静态函数(看起来,编译器会像
静态函数)

它之所以有效,是因为没有捕获的lambda的闭包类型提供了一个返回函数指针的转换运算符。这些运算符是可比较的。[expr.prim.lambda]/6(emphasis mine):

没有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;
    }
};

正如您可能已经注意到的,转换运算符每次都返回相同的函数指针。尽管如果发生类似情况,这将是完全令人惊讶的,但该标准允许为同一个闭包对象调用转换运算符返回不同的函数指针;因此,比较两个闭包对象会产生一个错误n实现定义的值。(但是,对于相同类型的两个闭包对象,在所有实现上都应该是
true
。)

好吧,现在很清楚了,为什么可以将lambda与空捕获列表进行比较。但是,如何将lambda与非空捕获列表进行比较的问题仍然没有答案。@alphashooter您到底想比较什么?即,应该比较lambda的哪些属性?例如,lambda是可复制构造的,但是如果我有两个副本对于相同的闭包,我无法使用相等运算符检查它们是否相等。@alphashooter无法比较它们。您无法访问闭包的成员变量,编译器也不会为您声明任何
运算符==
。这就是我想知道的。看起来,唯一的解决方案是比较它们的地址,但是需要避免创建副本。