2

我有一个实现重试机制的宏,如下所示:

#define RETRY(function_name, param_list, max_attempts, retry_interval_usecs, error_var) \
    do {                                                                                                   \
        int _attempt_;                                                                                     \        
                                                                                               \
        for (_attempt_ = 0; _attempt_ < max_attempts; _attempt_++)                                         \
        {                                                                                                  \
            error_var = function_name param_list;                                                          \
            if (error_var == SUCCESS)                                                         \
            {                                                                                              \
                break;                                                                                     \
            }                                                                                              \
                                                                                                           \
            usleep(retry_interval_usecs);                                                                  \
        }                                                                                                                                                                                                                                                                                                   \
    } while (0)

这是功能性的,但我一直听说在 C++ 应用程序中defines是不利的。

现在我研究了一个以函数指针作为参数的重试函数。但我似乎错过了一些东西,因为我无法编译这段代码。

注意:下面的这段代码是非功能性的,我想我可以发布一个简单的代码来说明我想要做什么:

void retry(int (*pt2Func)(void* args))
{
    const int numOfRetries = 3;
    int i = 1;
    do
    {
        //Invoke the function that was passed as argument
        if((*pt2Func)(args)) //COMPILER: 'args' was not declared in this scope
        {
          //Invocation is successful
          cout << "\t try number#" << i <<" Successful \n";
          break;
        }

        //Invocation is Not successful
        cout << "\t try number#" << i <<" Not Successful \n";
        ++i;

        if (i == 4)
        {
          cout<< "\t failed invocation!";
        }

    }while (i <= numOfRetries);
}

int Permit(int i)
{
    //Permit succeeds the second retry
    static int x = 0;
    x++;
    if (x == 2 && i ==1 ) return 1;
    else return 0;
}

int main()
{
    int i = 1;
    int * args = &i;


    retry(&Permit(args));
}

所以基本上我的问题是:

  • 如何将具有不同参数(类型和数量)的通用函数传递给重试方法?没有将函数封装在一个类中?

那可行吗?

4

5 回答 5

4

所有现有的答案都是 C++11,所以这里对你的代码做一个小的修改,使它可以使用 boost(它是 C++03)工作

//takes any function or function like object
//expected function takes no parameters and returns a bool
template<class function_type>
void retry(function_type function, int numOfRetries = 3)
{
    int i = 1;
    do
    {
        //Invoke the function that was passed as argument
        if(function())
            blah blah blah

主要是

int main()
{
    int i = 1;
    //bind takes a function and some parameters
    //and returns a function-like object with a different parameter set
    //in this case, the function Permit, and the first thing it gets passed is i
    //this means the resulting function-like object doesn't need any parameters
    //return type is the same as the original function
    retry(boost::bind(Permit, i));
}

C++03编译和执行的证明

于 2013-01-16T21:52:58.397 回答
1

以下解决方案使用了 C++11 功能 - 无法使用 C++11 的补充是在解决方案开发开始后完成的。

一种 C++ 方法是使用std::function.

以下代码给出了函数、“可调用”类和 lambda 表达式的示例。

#include <string>
#include <iostream>
#include <functional>
#include <unistd.h>

// Minimalistic retry 
bool retry( std::function<bool()> func, size_t max_attempts, 
    unsigned long retry_interval_usecs ) {
  for( size_t attempt { 0 }; attempt < max_attempts; ++attempt ) {
    if( func() ) { return true; }
    usleep( retry_interval_usecs );
  }
  return false;
}

// Ex1: function
int f(std::string const u) {
  std::cout << "f()" << std::endl;
  return false;
}

// Ex2: 'callable' class
struct A {

  bool operator() (std::string const & u, int z) {
    ++m_cnt;
    std::cout << "A::op() " << u << ", " << z << std::endl;

    if( m_cnt > 3 ) {
      return true;
    }
    return false;
  }

  int m_cnt { 0 };
};

int main() {

  A a;

  bool const r1 = retry( std::bind(f, "stringparam1"), 3, 100 );
  bool const r2 = retry( std::bind(a, "stringparam2", 77), 5, 300 );
  // Ex 3: lambda
  bool const r3 = retry( []() -> bool
    { std::cout << "lambda()" << std::endl; return false; }, 5, 1000 );

  std::cout << "Results: " << r1 << ", " << r2 << ", " << r3 << std::endl;

  return 0;
}

使用 gcc 4.7.2 对此进行了测试。输出:

f()
f()
f()
A::op() stringparam2, 77
A::op() stringparam2, 77
A::op() stringparam2, 77
A::op() stringparam2, 77
lambda()
lambda()
lambda()
lambda()
lambda()
Results: 0, 1, 0
于 2013-01-16T21:01:53.993 回答
1

有两种方法。

使用可变参数模板函数:

// All in header file:
template <typename F, typename... Args>
void retry1(F func, Args&& ... args) {
    //...
    if (func(std::forward<Args>(args)...))
    ; //...
}

// Call like:
retry1(Permit, i);

或使用 astd::function和 lambda:

// In header file
void retry2(std::function<bool()> func);

// In a source file
void retry2(std::function<bool()> func) {
    //...
    if (func())
    ; //...
}

// Call like:
retry2([]() -> bool { return Permit(i); });
于 2013-01-16T21:08:49.250 回答
0

好吧,如果您使用的是 C++11,那么您就有Lambda 表达式

还有这个问题:编写一个接受 lambda 表达式作为参数的函数,提供另一个相关示例。

看到你不能使用 C++11 后编辑

在这种情况下,我只会保留宏并忘记它。虽然有些人可能不喜欢它,但您有充分的理由使用它 - 它比其他解决方案更容易且更有意义。只需将其写在宏上方的评论中,这样 5 年后,当人们试图弄清楚为什么您决定不使用std:forward或 lambda 表达式时,他们就会知道。

于 2013-01-16T21:05:19.680 回答
0

FWIW,我正在尝试修复您的初始示例。(可能还有其他缺点,没有人会走这条路,因为有更好的解决方案)

您对重试的初始定义可以写成:

void retry(int (*pt2Func)(void* args), void* args)

它获取一个函数指针(指向返回的函数和 int 以及一个 void* 参数)和一个附加 (void*) 参数。

现在的Permit功能是:

int Permit(void* pvi)

主函数现在调用 retry/Permit 如下:

    retry(&Permit, static_cast<void*>(args));

完整示例

#include <iostream>
using std::cout;

void retry(int (*pt2Func)(void* args), void* args)
{
    const int numOfRetries = 3;
    int i = 1;
    do
    {
        //Invoke the function that was passed as argument
        if((*pt2Func)(args)) //not changed: args is now declared
        {
          //Invocation is successful
          cout << "\t try number#" << i <<" Successful \n";
          break;
        }

        //Invocation is Not successful
        cout << "\t try number#" << i <<" Not Successful \n";
        ++i;

        if (i == 4)
        {
          cout<< "\t failed invocation!";
        }

    }while (i <= numOfRetries);
}

int Permit(void* pvi)
{
    //Permit succeeds the second retry
    int i = *(static_cast<int*>(pvi));
    static int x = 0;
    x++;
    if (x == 2 && i ==1 ) return 1;
    else return 0;
}

int main()
{
    int i = 1;
    int * args = &i;

    retry(&Permit, static_cast<void*>(args));
}
于 2019-04-03T06:49:41.913 回答