我有C++代码包装任意lambda并返回lambda的结果.
template <typename F>
auto wrapAndRun(F fn) -> decltype(F()) {
// foo();
auto result = fn();
// bar();
return result;
}
Run Code Online (Sandbox Code Playgroud)
这有效,除非Freturn void(error: variable has incomplete type 'void').我想用a ScopeGuard来运行bar,但我不想bar在fn投掷时运行.有任何想法吗?
Nir*_*man 22
您可以编写一个简单的包装器类来处理它的这一部分:
template <class T>
struct CallAndStore {
template <class F>
CallAndStore(F f) : t(f()) {}
T t;
T get() { return std::forward<T>(t); }
};
Run Code Online (Sandbox Code Playgroud)
并专注:
template <>
struct CallAndStore<void> {
template <class F>
CallAndStore(F f) { f(); }
void get() {}
};
Run Code Online (Sandbox Code Playgroud)
您可以通过小型工厂功能提高可用性:
template <typename F>
auto makeCallAndStore(F&& f) -> CallAndStore<decltype(std::declval<F>()())> {
return {std::forward<F>(f)};
}
Run Code Online (Sandbox Code Playgroud)
然后使用它.
template <typename F>
auto wrapAndRun(F fn) {
// foo();
auto&& result = makeCallAndStore(std::move(fn));
// bar();
return result.get();
}
Run Code Online (Sandbox Code Playgroud)
编辑:内置std::forward强制转换get,这似乎也可以处理正确返回函数的引用.
Már*_*ldi 13
新的C++ 17 if constexpr添加在这里可能会有所帮助.您可以选择是否fn()在编译时返回结果:
#include <type_traits>
template <typename F>
auto wrapAndRun(F fn) -> decltype(fn())
{
if constexpr (std::is_same_v<decltype(fn()), void>)
{
foo();
fn();
bar();
}
else
{
foo();
auto result = fn();
bar();
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
正如你所说C++ 2a也是一个选项,你也可以使用概念,对函数施加约束:
template <typename F>
requires requires (F fn) { { fn() } -> void }
void wrapAndRun(F fn)
{
foo();
fn();
bar();
}
template <typename F>
decltype(auto) wrapAndRun(F fn)
{
foo();
auto result = fn();
bar();
return result;
}
Run Code Online (Sandbox Code Playgroud)
另一个技巧可能是利用逗号运算符,如:
struct or_void {};
template<typename T>
T&& operator,( T&& x, or_void ){ return std::forward<T>(x); }
template <typename F>
auto wrapAndRun(F fn) -> decltype(fn()) {
// foo();
auto result = ( fn(), or_void() );
// bar();
return decltype(fn())(result);
}
Run Code Online (Sandbox Code Playgroud)
您可以查看Alexandrescu的ScopeGuard:ScopeGuard.h它只在没有异常时才执行代码.
template<class Fn>
decltype(auto) wrapAndRun(Fn&& f) {
foo();
SCOPE_SUCCESS{ bar(); }; //Only executed at scope exit when there are no exceptions.
return std::forward<Fn>(f)();
}
Run Code Online (Sandbox Code Playgroud)
因此,在没有错误的情况下,执行顺序是:1.foo(),2. f(),3.bar().如果出现异常,订单为:1.foo(),2.f()
| 归档时间: |
|
| 查看次数: |
1932 次 |
| 最近记录: |