Reputation: 23
The goal that I want to achieve is for the program to stop the process and return a timeout error if the process exceeds the timeout time.
I got a timeout function from the second most voted answer to this question. I ran into an error which says that std::result_of_t
is deprecated in c++17, so I re-created it using the suggested replacement std::invoke_result_t
and implemented it like so:
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");
}
}
I wanted to use it to check for timeout on a class method's function. So I tried to use it in a way similar to:
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;
}
}
With this, I get the error:
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)
I think the problem is something similar to this entry but I have no idea how to correct it. Some functions that I need to use the timeout function on have different object parameters which is why a function template is used.
Thank you very much in advance for the help!
Upvotes: 1
Views: 571
Reputation: 30860
As the name suggests, std::invoke_result_t
is the result type of applying std::invoke
. I highlighted the case that applies to you here:
INVOKE(f, t1, t2, ..., tN) is defined as follows:
...
If f is a pointer to member function of class T:
- If std::is_base_of<T, std::decay_t<decltype(t1)>>::value is true, then INVOKE(f, t1, t2, ..., tN) is equivalent to (t1.*f)(t2, ..., tN)
- If t1 does not satisfy the previous items, then INVOKE(f, t1, t2, ..., tN) is equivalent to ((*t1).*f)(t2, ..., tN).
So your call should be:
retVal = run_with_timeout(&ClassOne::func, 20s, this, std::move(param1), std::move(name));
EDIT: I struggled for a good twenty minutes with getting it to actually work. Adding std::move
as above OR taking name
by const reference (in dummy
) makes it compile. I cannot think of a similar transformation for param1
. I would be very interested to know the reason behind that error, but at least your immediate problem is solved.
Upvotes: 1