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)

definesこれは機能しますが、C++ アプリケーション内では好ましくないと聞いています。

ここで、関数ポインターを引数として取る再試行関数を調べました。しかし、このコードをコンパイルできないため、何かを見逃しているようです。

注: 以下のコードは非機能的です。やりたいことを説明するために簡単なコードを投稿できると思いました。

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 であるため、ブースト (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

2つの方法があります。

可変個引数テンプレート関数の使用:

// 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とラムダを使用します。

// 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 に答える
1

次のソリューションはC++11の機能を使用しています。ソリューションの開発が開始された後、C++11を使用できないという追加が行われました。

C ++の1つの方法は、を使用することstd::functionです。

次のコードは、関数、「呼び出し可能」クラス、およびラムダ式の例を示しています。

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

これをgcc4.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 に答える
0

C++11 を使用している場合は、ラムダ式があります。

次の質問もあります。別の関連する例を提供する引数としてラムダ式を受け入れる関数を作成します。

C++ 11を使用できないことを確認した後に編集

その場合、私はマクロをそのままにして忘れます。一部の人々はそれを嫌うかもしれませんが、それを使用する正当な理由があります.それは他の解決策よりも簡単で理にかなっています. マクロの上のコメントにそれを書いてくださいstd:forward.

于 2013-01-16T21:05:19.680 に答える