【问题标题】:How to save a statically optional value如何保存静态可选值
【发布时间】:2013-09-16 08:20:02
【问题描述】:

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

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

【问题讨论】:

  • @Nawaz:是的,没关系:-S

标签: c++ perfect-forwarding


【解决方案1】:

执行你的函数返回是合法的:

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)...);
}

【讨论】:

  • 我也是这么想的。可以更好吗?说如果我想打印一些参数?然后我们必须将它们传递给构造函数,这使得它变得不那么有趣了。
  • 嗯,就是这样。实际上,如果出现异常,我特别不希望它执行。有std::uncaught_exception,它非常接近让这样的事情发挥作用……
  • @Potatoswatter 我一直在玩一些,但我仍然认为enable_if 在这种情况下可能更合适 - 我认为在出现异常时没有简单的方法来模拟相同的行为。但也许其他人在这方面取得了更大的成功。
【解决方案2】:

最简单的方法是在本地对象的析构函数中执行附加代码。这样做也允许直接传递结果,这可以省略复制/移动,否则需要 fir 非左值返回:

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)...);
}

【讨论】:

  • 这与其他答案相同。我相信由于异常而退出时,不可能使它的行为与原始行为相似,如果它是从堆栈展开中执行的。
【解决方案3】:

这里尝试将问题以至少可以重复使用的形式转移到专用包装器。

不确定正确性,甚至没有尝试编译过一次。至少,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 ) );
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-12
    • 1970-01-01
    • 1970-01-01
    • 2018-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-23
    相关资源
    最近更新 更多