捕获Lambda表达式异常

4

如何捕获作为异常抛出的lambda表达式?我尝试了以下方法:

#include <functional>
int main() {
    try {
        throw [](){};
    } catch (std::function<void()> & fn) {
        fn();
    }
}

然而输出结果为:

在抛出'main::{lambda()#1}'实例后终止调用

是否可能捕获抛出的lambda异常?


3
请记住,每个 lambda 都是其自己独特的类型,并且它没有任何共同的基础类型。此外,抛出 lambda 看起来似乎不是一个好主意。 - Some programmer dude
3
此外,通过抛出lambda函数,您想要解决的实际问题是什么?您向我们展示了一个针对未知问题的期望解决方案,并要求我们帮助您解决该解决方案,而没有告诉我们它应该解决什么问题。这是一个典型的XY问题(http://xyproblem.info/)。 - Some programmer dude
我实际上不会像那样编码,我只是想知道它在理论上是否可行。在我的真实代码中,我通常尽可能避免使用异常,所以不用担心 ;) - Anonymous Entity
如果您不关心实际值,但需要捕获它,那么总是可以使用catch(...)。您甚至可以稍后使用std::exception_ptr来进行一些技巧操作。 - milleniumbug
4个回答

4
你可以显式地使用 std::function
int main() {
    try {
        throw std::function<void()>([](){std::cout << "Hello there!";});
    } catch (std::function<void()> & fn) {
        fn();
    }
}

1
int main() {
    try {
        throw [](){};
    } catch (std::function<void()> & fn) {
        fn();
    }
}

以下是导致异常处理程序不会被执行的两个原因:

  1. 您通过对 std::function<void()> 对象的 lvalue 引用捕获异常,但抛出的对象既不是该类型,也不是该抛出对象的基类。

  2. 即使您将参数更改为值,std::function<void()> 也无法从异常处理中的 lambda 构造。请参见 this


然而,有方法可以使其“工作”。请参见 SingerOfTheFall skypjack的答案。


1
Lambda有自己的类型,不是std::function。因此你没有捕获lambda,而是捕获了另一些从未被抛出并且可以被赋值给std::function的东西。
为了解决这个问题,你可以直接将lambda包装在std::function或处理程序类中并抛出它。
作为一个最小的工作示例(使用一个包装器,写起来有点有趣):
#include <functional>
#include<utility>
#include<type_traits>
#include<iostream>

struct Base {
    virtual void operator()() = 0;
};

template<typename F>
struct Lambda: F, Base {
    Lambda(F &&f): F{std::forward<F>(f)} {}
    void operator()() override { F::operator()(); }
};

template<typename F>
auto create(F &&f) {
    return Lambda<std::decay_t<F>>{std::forward<F>(f)};
}

int main() {
    try {
        throw create([](){ std::cout << "doh" << std::endl; });
    } catch (Base &fn) {
        fn();
    }
}

0
捕获异常的主要要求是必须有一个特定类型的对象来进行捕获。Lambda表达式没有一个特定、干净的类型可以使用。一种干净的方法是将Lambda表达式包装在std::function中,这样你就确切地知道你正在捕获什么。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接