我有一个C++代码,它可以 Package 一个任意的lambda并返回lambda的结果。
template <typename F>
auto wrapAndRun(F fn) -> decltype(F()) {
// foo();
auto result = fn();
// bar();
return result;
}
除非F
返回void
(error: variable has incomplete type 'void'
),否则此函数有效。我曾想过使用ScopeGuard
来运行bar
,但我不希望在fn
抛出时运行bar
。有什么想法吗?
P.S.我后来发现有a proposal to fix this inconsistency。
7条答案
按热度按时间55ooxyrt1#
您可以编写一个简单的 Package 器类来处理这一部分:
并专门:
您可以使用一个小型工厂函数来提高可用性:
那就用它。
编辑:通过
get
内部的std::forward
强制转换,这似乎也可以正确处理从函数返回引用。nnsrf1az2#
新的C++17
if constexpr
加法在这里可能会有帮助。你可以选择是否在编译时返回fn()
的结果:正如你所说的C++20也是一个选项,你也可以利用概念,对函数施加约束:
t5fffqht3#
您可以查看Alexandrescu的ScopeGuard:ScopeGuard.h它只在没有异常时执行代码。
因此,在没有错误的情况下,执行顺序为:1. foo(),2. f(),3. bar()。如果出现异常,则顺序为:1. foo(),2. f()
juzqafwq4#
另一个技巧可能是利用逗号操作符,类似于:
bejyjqdl5#
SFINAE的解决方案,其思想是在内部使void函数实际返回int -希望编译器将优化这一点。在外部
wrapAndRun
将返回与 Package 函数相同的类型。http://coliru.stacked-crooked.com/a/e84ff8f74b3b6051
643ylb086#
解决这个问题最方便的方法是将
void
Package 成一个你可以实际使用的类型,沿着一个将void
转换成这个常规类型的std::invoke
版本。如果
fn()
不是void
,它会做和之前一样的事情,返回任何类型,如果fn()
* 是void
,那么result
的类型是vd::Void
,它只是一个空类型。这很方便,因为您将所有特殊情况的空处理放在一个位置(在本例中是库),然后剩下的代码看起来就正常了。你不必为每一种用法编写任何定制的特殊情况,你不必根据你选择的解决方案重新组织你的代码逻辑-您仍然可以在
fn
之前和之后调用foo()
和bar()
。plicqrtu7#
这是一个非常笨拙的、不可扩展的解决方案,但是非常简短,并且它支持RVO,这对于某些返回类型可能非常重要: