2

私はいくつかの信号/スロットの実装を見てきましたが、例外なくかなり複雑で、QtのようにMOCと追加のコード生成に依存しているものもあります。

脅威の安全性などの懸念があることは承知していますが、単純なシングルスレッドのシナリオの場合、次のような単純なアプローチを採用することに何か問題があります。

typedef void (*fPtr)();

class GenericButton
{
public:
    GenericButton() : funcitonToCall(nullptr) {}
    void setTarget(fPtr target) {
        funcitonToCall = target;
    }

    void pressButton() {
        if (funcitonToCall) funcitonToCall();
    }

private:
    fPtr funcitonToCall;
};

void doSomething(){
    std::cout << "doing something..." << std::endl;
}

void doSomethingElse(){
    std::cout << "doing something else..." << std::endl;
}

int main(){
    GenericButton myButton;
    myButton.setTarget(doSomething);
    myButton.pressButton();
    myButton.setTarget(doSomethingElse);
    myButton.pressButton();
}

他のいくつかのメソッドをチェーンして、ターゲットのvoid関数にデータを渡すことは引き続き可能です。それでは、ボタンがクリックされたときにコードを実行するのと同じくらい些細なことのすべての複雑さはなぜですか。

4

1 に答える 1

2

これは完全に賢明な解決策ですが、関数ポインタだけに制限しないでください。これを使用std::functionすると、物事をバインドし、オブジェクトのメンバー関数を呼び出し、ラムダを使用し、それでも意味のある関数ポインターに頼ることができます。例:

#include <iostream>
#include <functional>

using namespace std::placeholders;


class GenericButton
{
public:
    typedef std::function<void()> fPtr;
    GenericButton() : funcitonToCall(nullptr) {}
    void setTarget(fPtr target) {
        funcitonToCall = target;
    }

    void pressButton() {
        if (funcitonToCall) funcitonToCall();
    }

private:
    fPtr funcitonToCall;
};

struct foo {
    void doSomething() const {
        std::cout << "doing something in a foo..." << std::endl;
    }

    static void alternative(int i) {
        std::cout << "And another, i=" << i << "\n";
    }
};

void doSomethingElse() {
    std::cout << "doing something else..." << std::endl;
}

int main() {
    GenericButton myButton;
    foo f;
    myButton.setTarget(std::bind(&foo::doSomething, &f));
    myButton.pressButton();
    myButton.setTarget(doSomethingElse);
    myButton.pressButton();
    myButton.setTarget(std::bind(foo::alternative, 666));
    myButton.pressButton();
    myButton.setTarget([](){ std::cout << "Lambda!\n"; });
    myButton.pressButton();
}

ほとんどの場合、C++には関数ポインターよりも優れたソリューションがあります。

あなたが持っていない場合std::function/その仕事を後押しするための代替案が常にあり、あなたがこのようなものを作りたいならやる価値があるであろうあまり多くの仕事なしでstd::bindあなた自身の代替案を転がすことができます。std::function

信号/スロットメカニズムのほとんどは、そのようなものboost::bindが実行可能なオプションではなかった時代からのものです。当時はもう昔のことであり、関数ポインタだけでなく、標準的で柔軟性のあるものを少し複雑にすることができます。

于 2012-09-20T15:55:11.217 に答える