如何保存静态可选值

时间:2013-09-16 08:20:02

标签: c++ perfect-forwarding

考虑一个包装其他函数但在包装调用之后执行某些操作的函数。

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

3 个答案:

答案 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 ) );
}