Vit*_*meo 24 c++ copy-elision auto c++17 decltype-auto
(这是“ “ decltype(auto)变量是否有实际用例? ”的后续文章)
考虑以下情况-我想将一个函数传递f
给另一个函数invoke_log_return
,该函数将:
调用f
;
打印一些东西到stdout ;
返回的结果f
,避免不必要的复制/移动并允许复制省略。
请注意,如果f
抛出异常,则不应将任何内容打印到stdout。这是我到目前为止的内容:
template <typename F>
decltype(auto) invoke_log_return(F&& f)
{
decltype(auto) result{std::forward<F>(f)()};
std::printf(" ...logging here...\n");
if constexpr(std::is_reference_v<decltype(result)>)
{
return decltype(result)(result);
}
else
{
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
让我们考虑各种可能性:
当f
返回prvalue时:
result
将成为一个对象;
invoke_log_return(f)
将是一个prvalue(有资格使用复制省略)。
当f
返回左值或x值:
result
将作为参考;
invoke_log_return(f)
将是一个左值或x 值。
您可以在godbolt.org上看到一个测试应用程序。如您所见,g++
对prvalue情况执行NRVO ,而clang++
不会。
问题:
这是“完美地” decltype(auto)
从函数中返回变量的最短方法吗?有没有更简单的方法来实现我想要的?
可以在if constexpr { ... } else { ... }
图案中提取到一个单独的功能?提取它的唯一方法似乎是宏。
有什么充分的理由为什么clang++
不对上述prvalue案例执行NRVO ?应该将其报告为潜在的增强功能,还是g++
NRVO优化在此处不合法?
这是使用on_scope_success
助手的替代方法(如Barry Revzin所建议):
template <typename F>
struct on_scope_success : F
{
int _uncaught{std::uncaught_exceptions()};
on_scope_success(F&& f) : F{std::forward<F>(f)} { }
~on_scope_success()
{
if(_uncaught == std::uncaught_exceptions()) {
(*this)();
}
}
};
template <typename F>
decltype(auto) invoke_log_return_scope(F&& f)
{
on_scope_success _{[]{ std::printf(" ...logging here...\n"); }};
return std::forward<F>(f)();
}
Run Code Online (Sandbox Code Playgroud)
虽然invoke_log_return_scope
要短得多,但这需要对功能行为和新抽象的实现使用不同的思维模型。出人意料的是,两者g++
并clang++
用此溶液进行RVO /复印,省音。
正如Ben Voigt所提到的,这种方法的一个主要缺点是的返回值f
不能成为日志消息的一部分。
我们可以使用修改后的版本std::forward
:(避免名称转发以防止 ADL 问题)
template <typename T>
T my_forward(std::remove_reference_t<T>& arg)
{
return std::forward<T>(arg);
}
Run Code Online (Sandbox Code Playgroud)
该函数模板用于转发decltype(auto)
变量。它可以这样使用:
template <typename F>
decltype(auto) invoke_log_return(F&& f)
{
decltype(auto) result{std::forward<F>(f)()};
std::printf(" ...logging here...\n");
return my_forward<decltype(result)>(result);
}
Run Code Online (Sandbox Code Playgroud)
这样,如果std::forward<F>(f)()
返回
纯右值,则为result
非引用,并invoke_log_return
返回非引用类型;
一个左值,那么result
是一个左值引用,并invoke_log_return
返回一个左值引用类型;
xvalue,则为result
右值引用,并invoke_log_return
返回右值引用类型。
(基本上是从我的/sf/answers/4020857011/复制的)
归档时间: |
|
查看次数: |
437 次 |
最近记录: |