3

このトピックは何度も取り上げられているとあなたが言うのではないかと心配していますが、私は解決策を生み出すことができなかったので、あえて質問します. 探し方が悪かっただけなのかな…

外部関数から「モード」を受け取る関数があるとします。モードに応じて、関数は同じオブジェクトの異なるメンバー関数を呼び出します。これは、引数のないメンバー関数でうまく機能しますが、引数を持つメンバーに拡張する方法がわかりませんでした。実際のアプリケーションでは、引数は int/float ではなく、より複雑なクラスであり、呼び出しはさまざまなループ内にネストされているため、switch ステートメントを何度か配置する必要がありますが、これは見苦しいと思います。

質問 A: 既存の設計に基づいて、引数を持つメンバー関数のサポートを簡単に追加できますか? はいの場合、どのようにそれを行うのですか? 可能であれば、外部ライブラリなしで...

質問 B: これは完全に間違った/悪いアプローチですか? どうすればもっとうまくできますか?

あなたの助けと説明に感謝します。

クリス

ヘッダーの抜粋:

typedef void (Object::*memberFunction)();

class Object
{
    void memberFnNoArg();
    void memberFnWithIntArg(int arg);
    void memberFnWithFloatArg(float arg);
}

cpp の抜粋:

void function()
{
    int mode = getModeFromSomewhere();

    int intArg = 33;
    float floatArg = 66.6;

    switch(mode)
    {
    case 1:
        process(&Object::memberFnNoArg);
        break;
    case 2:
        process(&Object::memberFnWithIntArg, ???); // how can I pass arg?
        break;
    case 3:
        process(&Object::memberFnWithFlaotArg, ???); // how can I pass arg?
        break;
    default:
        // do nothing;
    }

}

void process(Object::memberFunction func)
{
    Object object;
    // loops, called several times, ...
    (object.*func)(); // how do I handle different arguments?
}
4

7 に答える 7

2

std::function と std::bind を見てください。必要なものに完全に適合しているようです。

編集:

std::function<void(Object &)> f = &Object::memberFnNoArg;
std::function<void(Object &)> f2 = std::bind(&Object::memberFnWithIntArg, _1, 22);

Object o;
f(o);
f2(o);

私が覚えている限り、箱から出して動作するはずです。これはあなたが必要とするものですか?

于 2013-06-04T09:54:55.920 に答える
2

アルゴリズムをファンクターにラップすることは正しいアプローチでありstd::function、標準ライブラリによって提供される優れたファンクターです。

しかし、Tomek が示唆しているように、 boost::bindorを使用するstd::bindことは、IMO にとって本当に醜いものであり、複数の引数をバインドするとすぐに制御不能になります。

最近のコンパイラを使用している場合は、代わりにラムダを使用できます。これにより、Tomek の例は次のようになります。

std::function<void(Object*)> f  =
    [](Object* const that){ that->memberFnNoArg(); };

int int_value = 22;
std::function<void(Object*)> f2 =
    [int_value](Object* const that){ that->memberFnIntArg(int_value); };

Object o;
f(&o);
f2(&o);

ラムダを設定する文字がいくつかありますが、メンバー アクセスの構文は非常に自然で、どのように変更するかは明らかです。

もちろん、必要に応じてパラメーターをオブジェクトへの参照にすることもできますが、ここではポインターを使用することをお勧めします。

于 2013-06-05T14:34:59.727 に答える
1

varadic テンプレート関数を使用できます。

template <typename... Args>
void process(void (Object::*func)(Args...),Args... args)
{
    Object object;

    // loops, called several times, ...
    (object.*func)(args...);
}

完全な例を次に示します。

#include <iostream>

struct Object
{
    void memberFnNoArg()
    {
      std::cout << "Object::memberFnNoArg()\n";
    }

    void memberFnWithIntArg(int arg)
    {
      std::cout << "Object::memberFnWithIntArg(" << arg << ")\n";
    }

    void memberFnWithFloatArg(float arg)
    {
      std::cout << "Object::memberFnWithFloatArg(" << arg << ")\n";
    }
};

template <typename... Args>
void process(void (Object::*func)(Args...),Args... args)
{
    Object object;

    // loops, called several times, ...
    (object.*func)(args...);
}

int main()
{
  process(&Object::memberFnNoArg);
  process(&Object::memberFnWithIntArg,5);
  process(&Object::memberFnWithFloatArg,2.7F);
  return 0;
}
于 2013-06-04T13:15:34.487 に答える
0

packaged_taskのように聞こえます。Tomek の提案もチェックしてください。

IRL ではありますが、そもそもなぜそれが必要なのかについて、たくさんの質問をしたいと思います。おそらくあなたの仕事は、std::futureまたは他のより高いレベルの施設を使用してよりよくカバーされる可能性があります.

于 2013-06-04T11:04:13.907 に答える
0

各関数 (memberFn**) を引数クラスのメンバーにすることはできませんか?

class BaseArg
{
  virtual void Fn() = 0;
};

class IntArg : public BaseArg
{
  void Fn();
};

class FloatArg : public BaseArg
{
  void Fn();
};


void function()
{
    int mode = getModeFromSomewhere();
    BaseArg* pArg;

    if ( mode ... ){
      pArg = new IntArg( 33 );
    }
    else {
      pArg = new FloatArg( 66.6 );
    }

    pArg->Fn();  // Call the right function without a switch
                 // and without knowing the arguments

}
于 2013-06-04T13:06:58.207 に答える
0

他の回答と同じですが、メンバーメソッドについて表示するには:

#include <iostream>
class Object
{
public:
    void memberFnNoArg()
    {
        std::cout << "Object::memberFnNoArg()\n";
    }

    void memberFnWithIntArg(int arg)
    {
        std::cout << "Object::memberFnWithIntArg(" << arg << ")\n";
    }

    void memberFnWithFloatArg(float arg)
    {
        std::cout << "Object::memberFnWithFloatArg(" << arg << ")\n";
    }
    bool memberFnWithBoolReturn(int)
    {
        return true;
    }
    template <typename... Args>
    void process(void (Object::*func)(Args...),Args... args);
    // overload process
    template <typename... Args>
    bool process(bool (Object::*func)(Args...),Args... args);
};
template <typename... Args>
void  process( void (Object::*func)(Args...),class Object* obj,Args... args)
{

    (obj->*func)(args...);
}
template <typename... Args>
bool  process( bool (Object::*func)(Args...),class Object* obj,Args... args)
{
    return ((obj->*func)(args...)) ;

}
int main()
{
    Object object;
    process(&Object::memberFnNoArg,&object);
    process(&Object::memberFnWithIntArg,&object,5);
    process(&Object::memberFnWithFloatArg,&object,2.7F);
    // overloaded process
    printf("%d\n",process(&Object::memberFnWithBoolReturn,&object,1));

    return 0;
}
于 2017-02-15T15:44:20.443 に答える