【问题标题】:Catching lambda exception捕获 lambda 异常
【发布时间】:2017-02-20 15:39:23
【问题描述】:

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

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

但是输出是

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

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

【问题讨论】:

  • 请记住,每个 lambda 都有自己独特的类型,并且没有任何共同的基本类型。此外,抛出 lambda 似乎是个坏主意。
  • 此外,您想通过抛出 lambda 来解决的实际问题是什么?你向我们展示了一个未知问题的想要的解决方案,并在没有告诉我们它应该解决什么的情况下向我们寻求解决方案的帮助。一个典型的XY problem
  • 我实际上不会那样编码,我只是想知道它是否可以在理论上起作用。我通常会尽可能避免在我的真实代码中出现异常,所以不用担心 ;)
  • 总是有catch(...),如果你不关心实际值,但需要抓住它。以后你甚至可以用std::exception_ptr 来耍花招。

标签: c++


【解决方案1】:

您可以明确抛出std::function

int main() {
    try {
        throw std::function<void()>([](){std::cout << "Hello there!";});
    } catch (std::function<void()> & fn) {
        fn();
    }
}

【讨论】:

    【解决方案2】:
    int main() {
        try {
            throw [](){};
        } catch (std::function<void()> & fn) {
            fn();
        }
    }
    

    异常处理程序不会被执行的两个原因:

    1. 您正在通过 lvalue 引用 std::function&lt;void()&gt; 的对象捕获异常,但抛出的对象不是该类型,也不是抛出对象的基类。

    2. 即使您将参数更改为值,std::function&lt;void()&gt; 也不会在异常处理中从 lambda 构造。见this


    但是,有一些方法可以让它“工作”。查看答案by SingerOfTheFallby skypjack

    【讨论】:

      【解决方案3】:

      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();
          }
      }
      

      【讨论】:

        【解决方案4】:

        捕获异常时的主要要求是为要捕获的对象具有特定类型。您可以使用 Lambda 的 don't have a specific, clean type。一个干净的方法是用 std::function 包裹你的 Lambda,然后你就知道你在捕捉什么了。

        【讨论】:

          猜你喜欢
          • 2013-04-20
          • 2016-03-10
          • 2017-06-14
          • 1970-01-01
          • 1970-01-01
          • 2014-10-07
          • 2019-05-06
          • 1970-01-01
          • 2014-11-24
          相关资源
          最近更新 更多