Krz*_*iak 55 c++ lambda exception
虽然最好只抛出从std::exception类派生的类型的异常,但C++可以抛出任何东西.以下所有示例都是有效的C++:
throw "foo"; // throws an instance of const char*
throw 5; // throws an instance of int
struct {} anon;
throw anon; // throws an instance of not-named structure
throw []{}; // throws a lambda!
Run Code Online (Sandbox Code Playgroud)
最后一个例子很有趣,因为它可能允许传递一些代码在catch站点执行,而不必定义单独的类或函数.
但是有可能抓住一个lambda(或一个闭包)吗?catch ([]{} e)不起作用.
Sto*_*ica 50
异常处理程序是基于类型匹配,并且完成以匹配一个异常对象到一个处理程序中的隐式转换比在其他上下文中更有限.
每个lambda表达式都引入了一个对于周围范围唯一的闭包类型.所以你的天真尝试无法工作,因为在throw表达式和处理程序中[]{}有一个完全不同的类型!
但你是对的.C++允许您抛出任何对象.因此,如果您事先将lambda显式转换为与异常处理程序匹配的类型,则它将允许您调用该任意可调用对象.例如:
try {
throw std::function<void()>{ []{} }; // Note the explicit conversion
} catch(std::function<void()> const& f) {
f();
}
Run Code Online (Sandbox Code Playgroud)
这可能有一个有趣的用途,但我要小心不要扔掉那些不是来自的东西std::exception.一个更好的选择可能是创建一个派生自std::exception并可以保持可调用的类型.
Mic*_*zel 23
C++允许你抛出任何东西.它可以让你抓住你扔的任何东西.当然,你可以扔一个lambda.唯一的问题是,为了捕捉某些东西,你需要知道那种东西的类型或至少是父类型.由于lambdas不是来自一个共同的基础,你必须知道你的lambda的类型来捕捉一个lambda.这个问题的主要问题是每个lambda表达式都会给你一个不同类型的rvalue .这意味着你的throw和catch都需要基于相同的lambda表达式(注意:相同的表达式,而不仅仅是一些看起来完全相同的表达式).我能想到的在某种程度上使这项工作的一种方法是封装lambda的创建以抛出一个函数.这样,您可以在throw表达式中调用该函数,并使用函数的返回类型将类型推导为catch:
#include <utility>
auto makeMyLambda(int some_arg)
{
return [some_arg](int another_arg){ return some_arg + another_arg; };
}
void f()
{
throw makeMyLambda(42);
}
int main()
{
try
{
f();
}
catch (const decltype(makeMyLambda(std::declval<int>()))& l)
{
return l(23);
}
}
Run Code Online (Sandbox Code Playgroud)
您也可以std::function在其他一些答案中使用类似的建议,这可能是一种更实用的方法.然而,其缺点是
std::function,这不是你要求的std::function从lambda 创建对象可能会抛出异常你可以抛出并抓住一个std::function:
#include <iostream>
#include <functional>
void f() {
throw std::function<void(void)>([]{std::cout << "lambda\n"; });
}
int main()
{
try{ f(); }
catch( std::function<void(void)> &e)
{
e();
std::cout << "catch\n";
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
lambda
catch
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2753 次 |
| 最近记录: |