我可以在 C++ 中创建匿名类并像在 Java 中一样捕获外部变量吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14368619/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can I create anonymous classes in C++ and capture the outside variables like in Java?
提问by woodings
In Java, when I need a callback function, I have to implement an anonymous class. Inside the anonymous class, I can access the outside variables if they're final
.
在Java中,当我需要一个回调函数时,我必须实现一个匿名类。在匿名类中,我可以访问外部变量,如果它们是final
.
Now I'm doing the same thing in C++. I understand that C++ lambda works better but sometimes I need to pass in many functions where with anonymous classes, I only need to pass in one instance.
现在我在 C++ 中做同样的事情。我知道 C++ lambda 工作得更好,但有时我需要传入许多带有匿名类的函数,我只需要传入一个实例。
I tried the following example. It works with GCC 4.3.4.
我尝试了以下示例。它适用于 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;
}
Is it possible to capture the outside variables like this?
是否可以像这样捕获外部变量?
int main() {
int y = 100; // mark y as final if possible
class : public IA {
int f(int x) { return x + y; }
} a;
return 0;
}
UPDATE:
更新:
The second example won't compile. The errors are here,
第二个例子不会编译。错误在这里,
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'
UPDATE:
更新:
I just realized a few more problems in doing this:
我刚刚意识到这样做还有几个问题:
- I cannot write a constructor because the class doesn't have a name
- initializer list doesn't allow inheritance.
- any change to make it compile makes the code unreadable.
- 我无法编写构造函数,因为该类没有名称
- 初始化列表不允许继承。
- 任何使其编译的更改都会使代码不可读。
I think I have to move away from anonymous classes.
我想我必须远离匿名课程。
采纳答案by Andy Prowl
There is no way to automaticallycapture those variables, but you can use an alternative approach. This is if you want to capture by reference:
无法自动捕获这些变量,但您可以使用替代方法。这是如果您想通过引用捕获:
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;
}
If you want to capture by value, just change int&
into int
.
如果要按值捕获,只需更改int&
为int
.
Anyway, you may consider using a tuple of lambdasas a "multi-callback" object if that is what bothers you about individual lambdas. You would still have everything packed in one object and capturing would be done for free.
无论如何,您可以考虑使用lambda 元组作为“多回调”对象,如果这让您对单个 lambda 感到困扰。您仍然可以将所有东西都打包在一个对象中,并且可以免费进行捕获。
Just as an example:
举个例子:
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...
);
回答by Jake Woods
You can capture the variable manually (which is similar to what a lambda capture does behind the scenes):
您可以手动捕获变量(这类似于 lambda 捕获在后台执行的操作):
int main() {
int y = 100;
struct {
int& y;
int operator()(int x) { return x + y; }
} anon = { y };
}
You can then use it like this:
然后你可以像这样使用它:
#include <iostream>
...
std::cout << anon(10) << std::endl;
Prints 110 as expected. Unfortunately you can't have the anonymous type inherit from another with this method as initializer-list constructable types can't inherit from another type. If inheritance is crucial then you should use the constructor method outlined by Andy Prowl.
按预期打印 110。不幸的是,您不能使用此方法从另一个匿名类型继承,因为初始化列表可构造类型不能从另一个类型继承。如果继承至关重要,那么您应该使用Andy Prowl 概述的构造函数方法。
回答by Jerry Coffin
A C++ lambda can capture "outside" variables. [Edit: when I first read the question, I somehow missed where he mentioned that he's aware of lambdas. For better or worse, C++ doesn't have anything else that really resembles an anonymous class].
C++ lambda 可以捕获“外部”变量。[编辑:当我第一次阅读这个问题时,我不知何故错过了他提到他知道 lambdas 的地方。不管是好是坏,C++ 没有任何其他真正类似于匿名类的东西]。
For example:
例如:
#include <iostream>
int main(){
int y = 100;
auto lambda = [=](int x) { return x + y; };
std::cout << lambda(2);
}
...prints 102
as its output.
...102
作为其输出打印。
Note that although it looks somewhat like a function, a C++ lambda really results in creating a class. I suppose I should add: that class isn't technically anonymous, but it has some unspecified name that's never directly visible.
请注意,虽然它看起来有点像一个函数,但 C++ lambda 确实会导致创建一个类。我想我应该补充一点:该类在技术上不是匿名的,但它有一些从未直接可见的未指定名称。
Edit: I'm still a bit puzzled about the justification for not using lambdas though. Is the intent to use one class that contains many member functions? If so, it's not clear how you plan to specify which member function to invoke at which time/for which purpose. My immediate reaction is that this sounds suspiciously as if you're trying to twist the language to support a problematic design.
编辑:我仍然对不使用 lambdas 的理由感到有些困惑。是否打算使用一个包含许多成员函数的类?如果是这样,则不清楚您计划如何指定在何时/出于何种目的调用哪个成员函数。我的直接反应是,这听起来很可疑,好像您试图扭曲语言以支持有问题的设计。
回答by Jay Hudson
It is not the anonymity of the class that restricts access to the outside variables. In the question, y is not accessible because the class was defined locally within a function.
限制访问外部变量的并不是类的匿名性。在问题中, y 不可访问,因为该类是在函数中本地定义的。
There are a couple of restrictions for classes defined locally. First, they can only access local variables that are static, but can access any other variable that is available to the scope of the function. Also, local classes can not have static data members.
本地定义的类有一些限制。首先,它们只能访问静态的局部变量,但可以访问函数范围内可用的任何其他变量。此外,本地类不能有静态数据成员。
As for anonymous classes, you can not have constructors nor destructors. All member functions must be declared inside the class definition. It can not have static static members, this includes const static integral members that normally can be instantiated inside of a class definition. Also inheritance is not allowed.
至于匿名类,你不能有构造函数和析构函数。所有成员函数都必须在类定义中声明。它不能有静态静态成员,这包括通常可以在类定义内实例化的 const 静态整数成员。也不允许继承。
Anonymous classes are an obscure corner of C++ and have little practical value. Lambda functions and other techniques are a lot more flexible. But who knows, perhaps in some situations it could help with code readability.
匿名类是 C++ 的一个不起眼的角落,几乎没有实用价值。Lambda 函数和其他技术要灵活得多。但谁知道呢,也许在某些情况下它可以帮助提高代码可读性。
回答by leftaroundabout
If your IA
class really has just one virtual method that you need to override (and the real complexity is other non-virtual methods) but you don't want to capture the local variables that this method needs, how about this:
如果你的IA
类真的只有一个你需要重写的虚拟方法(真正的复杂性是其他非虚拟方法),但你不想捕获这个方法需要的局部变量,那么这个怎么样:
int main() {
int y = 100;
auto f = [=](int x){return x+y;};
typedef decltype(f) F;
struct IB : IA {
F _f;
IB(F _f): _f(_f) {}
int f(int x) { return _f(x); }
} a(f);
doFancyWork(&a);
return 0;
}