通用重试机制 - 无法使用C ++ 11功能

问题描述 投票:2回答:5

我有一个宏,实现了一个看起来像这样的重试机制:

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

所以基本上我的问题是:

  • 如何将具有不同参数(类型和编号)的常规函数​​传递给重试方法?没有封装类中的函数?

那可行吗?

c++ function-pointers
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));
}

Proof of C++03 compilation and execution


0
投票

有两种方法。

使用可变参数模板函数:

// 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);

或使用std::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); });

0
投票

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

还有这个问题:Write a function that accepts a lambda expression as argument提供了另一个相关的例子。

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

在那种情况下,我只是保留宏并忘记它。虽然有些人可能会对它不屑一顾,但你有充分的理由使用它 - 它比其他解决方案更容易,更有意义。只需在宏上方的注释中写下,所以5年后当人们试图弄清楚为什么你决定不使用std:forward或lambda表达式时,他们就会知道。


0
投票

以下解决方案使用C ++ 11特性 - 在开始解决方案开发之后,无法使用C ++ 11。

一种C ++方式是使用std::function

下面的代码给出了函数,'callable'类和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

0
投票

FWIW,我正在尝试修复你的初始例子。 (可能还有其他缺点,没有人会采用这种方式,因为有更好的解决方案)

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

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

它获取一个函数指针(返回一个函数,返回int和一个void *参数)和一个额外的(void *)参数。

Permit函数现在是:

int Permit(void* pvi)

main函数现在调用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));
}
© www.soinside.com 2019 - 2024. All rights reserved.