我有一个宏,实现了一个看起来像这样的重试机制:
#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 ++ 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));
}
有两种方法。
使用可变参数模板函数:
// 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); });
好吧,如果您使用的是C ++ 11,那么就有Lambda Expressions。
还有这个问题:Write a function that accepts a lambda expression as argument提供了另一个相关的例子。
看到你不能使用C ++ 11编辑
在那种情况下,我只是保留宏并忘记它。虽然有些人可能会对它不屑一顾,但你有充分的理由使用它 - 它比其他解决方案更容易,更有意义。只需在宏上方的注释中写下,所以5年后当人们试图弄清楚为什么你决定不使用std:forward
或lambda表达式时,他们就会知道。
以下解决方案使用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
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));
}