Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/157.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在现代C+中使用try..catch块通过模板元编程包装任意函数调用+;_C++_Templates_C++11_Lambda_C++14 - Fatal编程技术网

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

C++ 在现代C+中使用try..catch块通过模板元编程包装任意函数调用+;,c++,templates,c++11,lambda,c++14,C++,Templates,C++11,Lambda,C++14,我想创建一些基本上应该包装其参数的模板。该参数应该是一个任意函数调用,它通过一些带有前缀和后缀代码的模板元编程魔术来包装 我想按如下方式使用它: auto result = try_call( some_vector.at(13) ); 而try\u调用将以某种方式定义,它将一个try..catch块包裹在某个向量的周围。at(13)。大概是这样的: template<typename T> // some template metaprogramming magic here t

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

我想按如下方式使用它:

auto result = try_call( some_vector.at(13) );
try\u调用
将以某种方式定义,它将一个try..catch块包裹在
某个向量的周围。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;
}
模板
//这里有一些模板元编程的魔力
试一试{
auto value=//在这里执行参数,即(13)处的某个_向量;
返回标准::实验::可选(值);
} 
捕获(标准::异常&){
返回std::实验::nullopt;
}
Bjarne Stroustrup的那篇论文,但它并没有准确描述我需要什么,我也没能找到解决这个问题的办法

如果这不能直接实现,我目前正在考虑通过一个模板函数来实现,该函数采用lambda:

template<typename Func>
auto try_call(Func f) {
    try {
        return f();
    } catch(std::exception&) {
        return std::experimental::nullopt;
    }
}
模板
自动重试调用(函数f){
试一试{
返回f();
}捕获(标准::异常&){
返回std::实验::nullopt;
}
}

但我不知道这是不是个好主意。我想兰博达有一些开销吧?我希望避免任何不必要的开销。

事实上,您使用lambda的解决方案非常好而且高效。从类型理论的角度来看,
try\u 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;
    }
}
模板
自动尝试调用(Func f)->std::experimental::optional{
试一试{
返回std::实验::使_可选(f());
}捕获(标准::异常&){
返回std::实验::nullopt;
}
}

用lambda调用它将在没有任何开销的情况下产生您想要的结果。lambda被编译成具有重载函数调用运算符的匿名结构。此结构用作
try\u调用
函数的模板参数。因此,编译器在调用
f()
时确切地知道要执行的函数,并且它将被内联。不涉及开销。

我一直在玩这个;这就是我提出的一个可能的解决方案

// Function
template<typename ReturnType, typename... Args, typename... UArgs>
ReturnType no_throw_call(ReturnType (*f)(Args...), UArgs... args)
{
    try { return f(args...); }
    catch (...) {}
    return ReturnType();
}

// Method
template<typename ReturnType, typename Class, typename... Args, typename... UArgs>
ReturnType no_throw_call_method(Class &c, ReturnType(Class::*m)(Args...), UArgs... args)
{
    try { return (c.*m)(args...); }
    catch (...) {}
    return ReturnType();
}
//函数
模板
ReturnType无抛出调用(ReturnType(*f)(Args…,UArgs…)
{
尝试{返回f(args…;}
捕获(…){}
ReturnType();
}
//方法
模板
ReturnType无抛出调用方法(类&c,ReturnType(类::*m)(Args…,UArgs…)
{
尝试{return(c.*m)(args…;}
捕获(…){}
ReturnType();
}
注意:当类型之间存在允许的转换时,如果类型与函数的签名不完全匹配,则使用UArgs允许自动转换类型

此外,此代码保证返回默认的初始化值

我建议,如果使用这种类型的代码,您应该在catch块中包含某种类型的错误日志记录。这可能会对客户隐藏您的bug,但您不想对开发人员和QA隐藏您的bug

事实上,我建议使用这个调试版本,以允许您的程序崩溃,就像它在QA测试期间应该做的那样。否则,您的客户可能会遇到一些不好的未定义行为,因为您隐藏了bug,所以无法找到它们

用法示例:

#define nt_strcpy(X,Y) no_throw_call(strcpy, (X), (Y))
nt_strcpy(nullptr, nullptr);

B b;
// this calls a method named do_it which takes an int as a parameter and returns void
no_throw_call_method<void>(b, &B::do_it, 1);
#定义nt#u strcpy(X,Y)不#u throw#u调用(strcpy,(X),(Y))
nt_strcpy(nullptr,nullptr);
B B;
//这将调用名为do_it的方法,该方法将int作为参数并返回void
无抛出调用方法(b,&b::do_it,1);

“我想lambda有一些开销?”你为什么这么说?lambda是这个问题的一个很好的解决方案。嗯,我认为与普通函数调用相比可能会有一些开销。我的意思是,
std::function
肯定会有开销,因为函子是压印出来的。我知道Lambda更高效,但我能确定这一点吗?lambda和直接调用方法一样便宜吗?在这种情况下,它们没有开销。无论如何,这一点是没有意义的,因为如果没有lambdas(或等效程序),您就无法实现这一点——可能没有使用宏。返回类型将需要显式设置。为什么这里需要
std::decation\t
?@j00hi
f()
可能会返回一个引用,这不适用于
optional
。要捕获c-runtime库中的异常,该异常将从strcpy(nullptr,nullptr)之类的调用中抛出,请使用/EHaYou进行编译。如果B::do_重载以返回不同签名的不同类型,则只需在模板中指定ReturnType:例如:void do_it(int i);int do_it();