考虑一个包装其他函数但在包装调用之后执行某些操作的函数。
template< typename ftor, typename ... args >
typename std::result_of< ftor( args ... ) >::type
call_and_report( ftor && f, args && ... a ) {
auto && ret{ f( std::forward< args >( a ) ... ) };
std::cout << "Done!\n";
return std::forward< typename std::result_of< ftor( args ... ) >::type >
( ret );
}
如何扩展它以包装返回void
的函数?添加另一个专业化很容易,但我正在寻找另一种可能是惯用的方式。
一般的想法是,可能有也可能没有价值。这就像编译时optional
。
答案 0 :(得分:4)
执行你的功能是合法的:
template <typename F, typename ... Args>
auto call_and_report(F && f, Args && ... a)
-> decltype(f(std::forward<Args>(a)...))
{
return f(std::forward<Args>(a)...);
}
现在要在通话后做一些事情,你可以在一个对象的析构函数中做到这一点:
template <typename F, typename ... Args>
auto call_and_report(F && f, Args && ... a)
-> decltype(f(std::forward<Args>(a)...))
{
struct execute { ~execute() { std::cout << "Done!" << '\n'; } } execute;
return f(std::forward<Args>(a)...);
}
答案 1 :(得分:1)
最简单的方法是在本地对象的析构函数中执行其他代码。这样做也允许直接传递结果,这可以忽略复制/移动否则需要非左值返回:
template <typename F, typename... Args>
...
call_and_forward(F&& f, Args&&... args) {
struct report {
~report() { std::cout << "done\n"; }
} reporter;
return f(std::forward<Args>(args)...);
}
答案 2 :(得分:0)
这是尝试将问题转移到专用包装器中,使其至少可以重复使用。
不确定是否正确,甚至没有尝试过编译一次。至少,static_cast
在按值返回时会生成不必要的副本。
我只是出于好奇,实际上并不需要解决这个问题,但看起来相当繁重。
template< typename ftor, typename ... args >
typename std::enable_if< ! std::is_void< typename std::result_of< ftor( args ... ) >::type >::value,
typename std::result_of< ftor( args ... ) >::type >::type
call_or_wrap_void( ftor && f, args && ... a )
{ return std::forward< ftor >( f ) ( std::forward< args >( a ) ... ); }
struct void_wrapper {};
template< typename ftor, typename ... args >
typename std::enable_if< std::is_void< typename std::result_of< ftor( args ... ) >::type >::value,
void_wrapper >::type
call_or_wrap_void( ftor && f, args && ... a ) {
std::forward< ftor >( f ) ( std::forward< args >( a ) ... );
return {};
}
template< typename ftor, typename ... args >
typename std::result_of< ftor( args ... ) >::type
call_and_report( ftor && f, args && ... a ) {
auto && ret{ call_or_wrap_void( std::forward< ftor >( f ), std::forward< args >( a ) ... ) };
std::cout << "Done!\n";
return static_cast< typename std::result_of< ftor( args ... ) >::type >
( std::move( ret ) );
}