在现代C++中使用try..catch块通过模板元编程包装任意函数调用

j00*_*0hi 5 c++ lambda templates c++11 c++14

我想创建一些基本上应该包装它的参数的模板.该参数应该是一个任意的函数调用,它通过一些模板元编程魔法包含前缀和后缀代码.

我想用它如下:

auto result = try_call( some_vector.at(13) );
Run Code Online (Sandbox Code Playgroud)

try_call会以某种方式定义,它周围包裹try..catch块some_vector.at(13).像这样的东西:

template<typename T>
// some template metaprogramming magic here
try {
    auto value = // execute the parameter here, i.e. some_vector.at(13);
    return std::experimental::optional<T>(value);
} 
catch (std::exception&) {
    return std::experimental::nullopt;
}
Run Code Online (Sandbox Code Playgroud)

有一篇关于Bjarne Stroustrup的论文,但这并不完全描述我需要什么,而且我无法找到解决这个问题的方法.

如果直接无法做到这一点,我现在正在考虑通过一个带有lambda的模板化函数来实现:

template<typename Func>
auto try_call(Func f) {
    try {
        return f();
    } catch(std::exception&) {
        return std::experimental::nullopt;
    }
}
Run Code Online (Sandbox Code Playgroud)

但我不知道这是不是一个好主意.我想,lambda有一些开销吗?我想避免任何不必要的开销.

gex*_*ide 5

实际上,你的lambda解决方案是非常好的和有效的.从类型理论的角度来看,try_call是一个更高阶的函数:它将另一个函数作为参数并在try catch上下文中执行它.

template<typename Func>
auto try_call(Func f) -> std::experimental::optional<std::decay_t<decltype(f())>> {
    try {
        return std::experimental::make_optional(f());
    } catch(std::exception&) {
        return std::experimental::nullopt;
    }
}
Run Code Online (Sandbox Code Playgroud)

用lambda调用它会产生你想要的东西而没有任何开销.lambda被编译为具有重载函数调用运算符的匿名结构.此结构用作try_call函数的模板参数.因此,编译器确切地知道调用时要执行的函数,f()它将被内联.不涉及任何开销.