我已经在C++ 11中编写了一个通用的指数补偿重试循环。我正在使用std::function传递可调用项以重试循环。如果callable函数返回true,则将重试isRetriable

#include <algorithm>
#include <cassert>
#include <chrono>
#include <functional>
#include <iostream>
#include <thread>

constexpr int64_t max_backoff_milliseconds = 30000; // 30 seconds

template <class R, class... Args>
R Retry(int max_retry_count, int64_t initial_dealy_milliseconds,
    const std::function<bool(R)> &isRetriable,
    const std::function<R(Args...)> &callable, Args &&... args)
{
    int retry_count = 0;
    while (true) {
        auto status = callable(std::forward<Args>(args)...);
        if (!IsRetriable(status)) {
            return status;
        }

       if (retry_count >= max_retry_count) {
           // Return status and abort retry
           return status;
       }
       int64_t delay_milliseconds = 0;
       if (initial_dealy_milliseconds > 0) {
           delay_milliseconds =
               std::min(initial_dealy_milliseconds << retry_count,
                     max_backoff_milliseconds);
       }
       std::cout << "Callable execution failed. Retry Count:"
              << retry_count + 1 << std::endl;
       std::this_thread::sleep_for(
           std::chrono::milliseconds(delay_milliseconds));
      retry_count++;
   }
}

bool isRetriable(int status) {
    if (status == 5)
       return true;
    return false;
}

int foo(int x, int y) {
    static int a = 1;
    a += (x + y);
    return a / 6;
}

int main() {
    auto result = Retry(1000, 100, isRetriable, foo, 1, 3);
    std::cout << result << std::endl;
    return 0;
}

编译时,出现以下错误:
prog.cpp: In function ‘int main()’:
prog.cpp:50:71: error: no matching function for call to ‘Retry(int,
int, bool (&)(int), int (&)(int, int), int, int)’
auto result = Retry<int, int, int>(1000, 100, isRetriable, foo, 1, 3);
                                                                   ^
prog.cpp:11:3: note: candidate: template<class R, class ... Args> R
Retry(int, int64_t, const std::function<bool(R)>&, const
std::function<_Res(_ArgTypes ...)>&, Args&& ...)
R Retry(int max_retry_count,
^~~~~
prog.cpp:11:3: note:   template argument deduction/substitution failed:
prog.cpp:50:71: note:   mismatched types ‘const
std::function<int(_ArgTypes ...)>’ and ‘int(int, int)’
auto result = Retry<int, int, int>(1000, 100, isRetriable, foo, 1, 3);
                                                                   ^

有人可以向我解释为什么我有这个错误吗?

最佳答案

我敢肯定这有很好的重复,但是...

这是一个较短的复制品:

template <typename T> void foo(std::function<bool(T)> ) { }
bool maybe(int ) { return false; }

foo(maybe); // error: no matching function call to 'foo(bool (&)(int))'

您可能会问-什么? maybe是可以通过返回T的某些bool调用的。但这不是模板推论的工作原理。为了根据参数推导std::function<bool(T)>,该参数必须是std::functionmaybe不是std::function,它只是一个函数,因此推论失败。任何具有不同表达方式的推论也会失败:
foo([](int ) { return true; }); // also error

基本上,试图推断出std::function几乎总是错误的事情。首先,这是错误的,因为它不起作用。其次,这是错误的,因为即使它确实起作用了,您也会在可能不需要它的环境中进行类型擦除。

相反,您想做的是推导出任意可调用对象,然后根据这些可调用对象确定其他这些参数是什么。 callable的返回类型就是使用callable调用Args...时得到的,并且您想确保isRetriable是该类型的谓词。

一种解决方法是:
template <typename Predicate, typename Callable, typename... Args,
    // figure out what the callable returns
    typename R = std::decay_t<std::invoke_result_t<Callable&, Args...>>,
    // require that Predicate is actually a Predicate
    std::enable_if_t<
        std::is_convertible_v<std::invoke_result_t<Predicate&, R>, bool>,
        int> = 0>
R Retry(int max_retry_count, int64_t initial_dealy_milliseconds,
    Predicate&& isRetriable,
    Callable&& callable,
    Args&&... args)
{
    // ....
}

关于c++ - 通用指数退避重试机制C++ 11,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50049996/

10-11 23:05
查看更多