【问题标题】:C++ Implementing a timeout function template for class methodsC++为类方法实现超时函数模板
【发布时间】:2021-01-21 02:47:15
【问题描述】:

我想要达到的目标是让程序停止进程并在进程超过超时时间时返回超时错误。

我从second most voted answer to this question 获得了超时功能。我遇到了一个错误,指出 std::result_of_t 在 c++17 中已弃用,所以我使用建议的替换 std::invoke_result_t 重新创建它并像这样实现它:

template <typename TF, typename TDuration, class... TArgs>
std::invote_result_t<TF&&, TArgs&&...> run_with_timeout(TF&& f, TDuration timeout, TArgs&&... args)
{
    using R = std::invoke_result_t<TF&&, TArgs&&...>;
    std::packaged_task<R(TArgs...)> task(f);
    auto future = task.get_future();
    std::thread thr(std::move(task), std::forward<TArgs>(args)...);
    if (future.wait_for(timeout) != std::future_status::timeout)
    {
       thr.join();
       return future.get(); // this will propagate exception from f() if any
    }
    else
    {
       thr.detach(); // we leave the thread still running
       throw std::runtime_error("Timeout");
    }
}

我想用它来检查类方法函数的超时。所以我尝试以类似的方式使用它:

template <typename TF, typename TDuration, class... TArgs>
std::invote_result_t<TF&&, TArgs&&...> ClassOne::run_with_timeout(TF&& f, TDuration timeout, TArgs&&... args)
{
    using R = std::invoke_result_t<TF&&, TArgs&&...>;
    std::packaged_task<R(TArgs...)> task(f);
    auto future = task.get_future();
    std::thread thr(std::move(task), std::forward<TArgs>(args)...);
    if (future.wait_for(timeout) != std::future_status::timeout)
    {
       thr.join();
       return future.get(); // this will propagate exception from f() if any
    }
    else
    {
       thr.detach(); // we leave the thread still running
       throw std::runtime_error("Timeout");
    }
}

// The function checked for timeout
int ClassOne::func(ClassTwo *param1, std::string name)
{
    // Some code here...

    // For mimicking function process:
    std::this_thread::sleep_for(10s);
    return 0;
}

// Function which calls the timed process with timeout function
int ClassOne::dummy(ClassTwo *param1, std::string name)
{
    int retVal = 0; // zero for no error, non-zero for error
    try
    {
        retVal = run_with_timeout(func, 20s, param1, name);
    }
    catch (runtime_error & e)
    {
        return 1;
    }
}

有了这个,我得到了错误:

no instance of function template "ClassOne::run_with_timeout" matches the argument list
    argument types are: (int (ClassTwo *param1, std::string target), std::chrono::seconds, ClassTwo *, std::string)

我认为问题类似于this entry,但我不知道如何纠正它。我需要使用超时函数的一些函数具有不同的对象参数,这就是使用函数模板的原因。

非常感谢您的帮助!

【问题讨论】:

  • 您的func 是静态的吗?如果不是,则需要将指向ClassOne 对象(例如this)的指针作为第一个参数传递。
  • @Botje func 不是静态的。如果不是太多,你能用上面的代码作为参考的例子来详细说明一下吗? run_with_timeout 函数模板会是什么样子?如何在 run_with_timeout 中调用 ClassOne::func? template &lt;class TC, typename TF, typename TDuration, class... TArgs&gt; std::invote_result_t&lt;TF&amp;&amp;, TArgs&amp;&amp;...&gt; ClassOne::run_with_timeout(TC *className, TF&amp;&amp; f, TDuration timeout, TArgs&amp;&amp;... args)上面的代码哪里错了?非常感谢!

标签: c++ templates timeout c++17 member-functions


【解决方案1】:

顾名思义,std::invoke_result_t 是应用std::invoke 的结果类型。我在这里强调了适用于您的案例:

INVOKE(f, t1, t2, ..., tN) 定义如下:
...
如果 f 是指向类 T 的成员函数的指针:

  • 如果 std::is_base_of>::value 为真,则 INVOKE(f, t1, t2, ..., tN) 等价于 (t1.* f)(t2, ..., tN)
  • 如果 t1 不满足前面的项,则 INVOKE(f, t1, t2, ..., tN) 等价于 ((*t1).*f)(t2, ..., tN)。

所以你的电话应该是:

retVal = run_with_timeout(&ClassOne::func, 20s, this, std::move(param1), std::move(name));

编辑:我挣扎了整整二十分钟才让它真正发挥作用。如上所述添加std::move 或通过const 引用获取name(在dummy 中)使其编译。对于param1,我想不出类似的转换。我很想知道这个错误背后的原因,但至少你的直接问题得到了解决。

【讨论】:

  • 能否添加std::bind 和 lambda 解决方案?对不起,这些对我来说都是新的。我尝试了您建议的解决方案,但它仍然输出相同的错误。我尝试了retVal = run_with_timeout(&amp;func, 20s, this, param1, name);(使用this*this),它消除了智能感知错误,但在构建后仍然输出相同的错误。按原样传递 func 输出错误 use '&amp;' to create a pointer to member 并传递 &amp;func 输出 '&amp;': illegal operation on bound member function expression
  • 哇,它现在工作了!非常感谢@Botje!如果我可以问,研究这些的最佳参考资料是什么?我想了解更多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-22
  • 1970-01-01
  • 2016-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-01
相关资源
最近更新 更多