提问人:Edward Falk 提问时间:2/8/2022 最后编辑:Edward Falk 更新时间:2/8/2022 访问量:231
如何将封盖包裹在封盖中?
How can I wrap a closure in a closure?
问:
这是我的特定用例,但我相信还有其他用例:
我将回调闭包传递给可能在不同线程中运行的函数。闭包中的代码可能会引发异常。我不希望这个例外杀死我的程序。我很高兴抓住它并报告它。(是的,我知道这样做可能会导致资源泄漏;我现在忽略了这个问题。
我的代码中有数百个这样的闭包,所以我不想编辑它们中的每一个来添加 try...catch 子句。我宁愿在闭包周围有一个简短的包装。
我的示例代码如下所示:
#include <iostream>
#include <thread>
using namespace std;
int
main()
{
string str("Hello, world");
// Program will die because of exception thrown in handler.
context->invoke(
[str](bool success) {
cout << str << ": " << success << endl;
throw exception();
}
);
myThread.join();
// I want my program to not die
context->invoke(
[]{exceptionCatcher(
[str](bool success) {
cout << str << ": " << success << endl;
throw exception();
}
);}
);
myThread2.join();
return 0;
}
然后我的模板看起来像这样:exceptionCatcher
template<typename Func>
void exceptionCatcher(Func func)
{
try {
func();
}
catch (const exception& e) {
cout << "Caught exception\n";
}
}
除了编译器不喜欢这样。
c++ -std=c++17 -o tester tester.cpp
tester.cpp:40:14: error: variable 'str' cannot be implicitly captured in a lambda with no
capture-default specified
[str]{
^
tester.cpp:23:12: note: 'str' declared here
string str("Hello, world");
^
tester.cpp:39:9: note: lambda expression begins here
[]{exceptionCatcher(
写什么魔法咒语?exceptionCatcher
复杂功能:有许多这样的“调用”函数。捕获的值和闭包的参数各不相同。是否可以编写一个处理所有这些情况的包装器?
答:
2赞
Jason
2/8/2022
#1
你的 lambda 不会是一个指针。它总是按值传递。
template <typename Func>
void exceptionCatcher(Func func)
{
//...
}
评论
1赞
Edward Falk
2/8/2022
谢谢;这几乎奏效了。问题在于内部闭包捕获一个值 ()。仅当外部闭包捕获相同的变量时,这才有效。可悲的是,我怀疑我在那里别无选择。[str]
0赞
Remy Lebeau
2/8/2022
您实际上不需要使用 lambda 来调用 ,因为接受任何可调用对象,包括函数,例如:demo。或者:演示exceptionHandler()
std::thread
auto func = [str]{ ... }; myThread2(exceptionCatcher<decltype(func)>, func);
void exceptionCatcher(std::function<void()> func) { ... func(); ... } thread myThread2(exceptionCatcher, [str]{ ... });
0赞
Edward Falk
2/8/2022
好的,它编译并在我的系统上运行。它取决于 std::thread 的构造函数,该构造函数分别采用函数指针和参数。我的实际用例是 std::thread 的包装器,我不确定包装器是否可以接受这些参数。在我测试它时待命。
0赞
Edward Falk
2/8/2022
我想我犯了过于简单化的罪。我将编辑我的问题以更准确地反映我的用例。
1赞
Remy Lebeau
2/8/2022
#2
您没有在外部 lambda 中捕获,因此它在内部 lambda 中不可用。str
如果允许你单独传递可调用对象及其参数(如 的构造函数允许),那么你可以做这样的事情:invoke()
std::thread
template<typename Func>
void exceptionCatcher(Func func)
{
try {
func(success);
}
catch (const exception& e) {
cout << "Caught exception\n";
}
}
auto func = [str](bool success) {
cout << str << ": " << success << endl;
throw exception();
};
context->invoke(
exceptionCatcher<decltype(func)>,
func
);
或者:
void exceptionCatcher(std::function<void(bool)> func)
{
try {
func(success);
}
catch (const exception& e) {
cout << "Caught exception\n";
}
}
context->invoke(
exceptionCatcher,
[str](bool success){
cout << str << ": " << success << endl;
throw exception();
}
);
否则,如果这不是一个选项,您只需要向外部 lambda 添加一个额外的捕获:
context->invoke(
[str]{ // <-- add this
exceptionCatcher(
[str](bool success) {
cout << str << ": " << success << endl;
throw exception();
}
);
}
);
评论
0赞
Edward Falk
2/8/2022
好的,谢谢,我以为这就是我要去的地方。我玩弄了使用 ,但我知道使用它有很大的开销。std::function()
评论
throw exception();
str