我可以在C++中创建匿名类并捕获像Java中的外部变量吗?

woo*_*ngs 37 c++ lambda anonymous-class c++11

在Java中,当我需要一个回调函数时,我必须实现一个匿名类.在匿名类中,我可以访问外部变量final.

现在我在C++中做同样的事情.我理解C++ lambda工作得更好但有时候我需要传入许多带有匿名类的函数,我只需要传入一个实例.

我尝试了以下示例.它适用于GCC 4.3.4.

class IA {
public:
  virtual int f(int x) = 0;  
};

int main() {
    class : public IA {
        int f(int x) { return x + 1; }
    } a;
    doFancyWork(&a);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

有可能像这样捕获外部变量吗?

int main() {
    int y = 100; // mark y as final if possible
    class : public IA {
        int f(int x) { return x + y; }
    } a;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

更新:

第二个例子不会编译.错误在这里,

prog.cpp: In member function ‘virtual int main()::<anonymous class>::f(int)’:
prog.cpp:9: error: use of ‘auto’ variable from containing function
prog.cpp:7: error:   ‘int y’ declared here
prog.cpp: In function ‘int main()’:
prog.cpp:7: warning: unused variable ‘y’
Run Code Online (Sandbox Code Playgroud)

更新:

我刚刚意识到这样做的一些问题:

  • 我无法编写构造函数,因为该类没有名称
  • 初始化列表不允许继承.
  • 任何使其编译的更改都会使代码无法读取.

我想我必须离开匿名课程.

And*_*owl 37

无法自动捕获这些变量,但您可以使用其他方法.如果您想通过引用捕获:

int main() {
    int y = 100; // mark y as final if possible
    class IB : public IA {
    public:
      IB(int& y) : _y(y) {}
      int f(int x) { return x + _y; }
    private:
      int& _y;
    } a (y);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果您想按值捕获,只需更改int&int.

无论如何,你可以考虑使用lambdas元组作为"多回调"对象,如果这是困扰你的个别lambdas.您仍然可以将所有内容打包在一个对象中,并且可以免费进行捕获.

举个例子:

auto callbacks = make_tuple(
    [] (int x) { cout << x << endl; },
    [&] () { cout << y << endl; }, // y is captured by reference
    [=] (int x) { cout << x + y << endl; }, // y is captured by value
    // other lambdas here, if you want...
    );
Run Code Online (Sandbox Code Playgroud)

  • 为lambdas元组+1.这是解决手头问题的一个非常优雅的解决方案. (3认同)

Jak*_*ods 8

您可以手动捕获变量(类似于lambda捕获在幕后执行的操作):

int main() {
    int y = 100;
    struct { 
        int& y;
        int operator()(int x) { return x + y; }
    } anon = { y };
}
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

#include <iostream>
...
std::cout << anon(10) << std::endl;
Run Code Online (Sandbox Code Playgroud)

按预期打印110.不幸的是,您不能使用此方法从另一个继承匿名类型,因为初始化列表可构造类型不能从其他类型继承.如果继承是至关重要的,那么你应该使用Andy Prowl概述构造函数方法.


Jer*_*fin 5

C++ lambda可以捕获"外部"变量.[编辑:当我第一次看到这个问题时,我不知何故错过了他提到他知道lambdas的地方.无论好坏,C++没有任何其他真正类似于匿名类的东西].

例如:

#include <iostream>

int main(){ 

    int y = 100;
    auto lambda = [=](int x) { return x + y; };

    std::cout << lambda(2);
}
Run Code Online (Sandbox Code Playgroud)

...打印102作为输出.

请注意,尽管它看起来有点像函数,但C++ lambda确实会导致创建一个类.我想我应该补充一点:该类在技术上并不是匿名的,但它有一些从未直接可见的未指定名称.

编辑:我仍然有点不知道不使用lambdas的理由.是否意图使用包含许多成员函数的一个类?如果是这样,则不清楚您计划如何指定在哪个时间/为何目的调用哪个成员函数.我的直接反应是,这听起来很可疑,好像你试图扭曲语言来支持有问题的设计.

  • 他似乎很清楚这一点,但不想使用lambda,因为他希望它能够同时封装许多不同的函数.虽然我不得不从内心深处反对他的方法,并且还建议只使用lambdas,但你的答案仍然没有真正回答实际问题. (2认同)