1

私は次のように非常に単純なクラス定義を持っています:

#include "../bshttp/controllers.h"
#include <iostream>
#include <string>

class DerivedController : public BS_Controllers
{
  public:
    DerivedController():BS_Controllers(this)
    {
        m_urlRules["print"] = REG_NAME &DerivedController::print;
        //regController(REG_NAME &DerivedController::print,"print");
        regController(REG_NAME &DerivedController::printView,"printView");
    }
    void * print()
    {
        return NULL;
    }
    void * printView()
    {
        cout<<"Print view!"<<endl;
        return NULL;
    }
};

ここでどちらか

 m_urlRules["print"] = REG_NAME &DerivedController::print;

また

 regController(REG_NAME &DerivedController::printView,"printView");

すべてのメンバー関数に対して呼び出す必要があります。クラスのメンバー関数ポインタを取り、文字列でマップするので、後で関数を文字列で識別できます。

すべてが正常に機能していますが、クラス構造が大きくなると、プログラマーはすべてのメンバー関数に対してこの関数を繰り返し呼び出す必要があります。とにかくプリプロセッサ、またはブーストウェーブなどの前処理ライブラリを使用して、プログラマーがこれらの繰り返しの呼び出しを行う必要がないようにすることはできますか?

編集:混乱して申し訳ありませんが、私は明らかにここで問題を十分に説明していませんでした。文字列をメンバー関数ポインタにマッピングしています。

m_urlRulesは文字列をキーとするstd::mapであり、メンバー関数ポインターを値としてregControllerは基本的にm_urlRulesのセッター関数であるため、両方のステートメントは事実上同じことを行い、文字列をメンバー関数にマップします。

REG_NAMEは、非常に醜い型キャストを置き換えるマクロです。

私がやろうとしているのは、クラスが次の構造を持つ場合、

class DerivedController : public BS_Controllers
{
  public:
    DerivedController():BS_Controllers(this);
    void * print();
    void * print2();
    void * print3();
    void * print4();
};

コンストラクターで次のことを行う必要はありません。

 m_urlRules["print"] = REG_NAME &DerivedController::print;
 m_urlRules["print1"] = REG_NAME &DerivedController::print1;
 m_urlRules["print2"] = REG_NAME &DerivedController::print2;
 m_urlRules["print3"] = REG_NAME &DerivedController::print3;
 m_urlRules["print4"] = REG_NAME &DerivedController::print4;
4

4 に答える 4

0

あなたの問題を完全に理解したかどうかは正確にはわかりませんが、キー(文字列)にマップできるマップなどの組み込みデータ構造を使用しないのはなぜですか。

ここにいくつかの例があります

于 2012-08-11T01:56:56.990 に答える
0

問題が発生する場所を確認するために、ログ記録の理由でこの機能を使用したいと思います。

私はあなたが次のようなものを探していると思います:

urlRules     ("<function name>");
regController("<function name>");

それ以外の

m_urlRules["<function name>"] = REG_NAME &DerivedController::print;
regController(REG_NAME &DerivedController::printView,"<function name>");

あなたはそのようなマクロスを次のように定義することができます:

#define      urlRules(x) { m_urlRules[(x)] = REG_NAME &DerivedController::print; }
#define regController(x) { regController(REG_NAME &DerivedController::printView,(x)); }

注意:私はそれをテストしていません、それはうまくいかないかもしれませんが、私の理解ではそれはそうあるべきです。

編集

ああ、わかりました。コンストラクター内のすべての関数を呼び出す必要があります。実際、コンストラクターは、作成するすべてのオブジェクトに対して呼び出されるため、間違った場所ですが、このポインターを割り当てる必要があるのは1回だけです。(たとえば起動時)

参照してください。クラスの関数はメモリ内に1回だけ存在し、ポインタに接続されているのはyieldデータであるため、すべてのメンバー変数です。

すべてのクラスメンバーを名前で取得して、それらを実行する簡単な方法はありません。申し訳ありません。少なくとも私が知っているようには。

ただし、特定のオブジェクトの関数ポインタは変更されないことに注意してください。仕事をする外部機能はもっと賢いでしょう。起動時に呼び出されます。

于 2012-08-11T02:08:50.193 に答える
0

さて、あなたは自分で実行時型情報(RTTI)を構築しようとしているので、このためのプリプロセッサマクロはありません。主な理由は、プリプロセッサマクロが単一の場所に展開され、宣言する場所と関数を登録する場所が異なるためです。

Qtとqmakeは、このようなことを行い、signals / slotとマークされた関数を見つけて、RTTI用のmocオブジェクトを構築します。これは、C++で得られる最高のものです。javaやdelphiなどの他の言語は、c ++よりも多くのRTTIを備えており、実行時に関数を照会することができます。

于 2012-08-11T02:12:40.993 に答える
0

私は最初に醜い型キャストを削除することに取り組みます(マクロ形式でも)。これは、中間(またはプロキシ)テンプレートクラスのm_urlRules外に移動することで実行できます。BS_Controllersテンプレートは、マップを適切な派生タイプに解決するために使用されます。(私はあなたがどのように定義したかわからなかったBS_Controllersので、私はそれを作りました。)

class BS_Controllers {
protected:
    virtual ~BS_Controllers () {}
public:
    virtual void * invokeRule (const std::string &) = 0;
};

template <typename D>
class BS_Proxy : public BS_Controllers {
    typedef std::map<std::string, void *(D::*)()> UrlRuleMap;

    static UrlRuleMap & urlRules () {
        static UrlRuleMap urlRules_;
        return urlRules_;
    }

    void * invokeRule (const std::string &s) {
        typename UrlRuleMap::iterator i = urlRules().find(s);
        if (i == urlRules().end()) return 0;
        return (dynamic_cast<D *>(this)->*(i->second))();
    }

protected:
    static void regController (void *(D::*m)(), const std::string &s) {
        urlRules()[s] = m;
    }
};

これで、プロキシクラスDerivedControllerのメソッドを呼び出すことで、をかなり簡単に初期化できます。regController

#define REG_RULE(D, x) BS_Proxy<D>::regController(&D::x, #x)

class DerivedController : public BS_Proxy<DerivedController> {
    struct Populate {
        Populate () {
            REG_RULE(DerivedController, print);
            REG_RULE(DerivedController, printView);
        }
    };
public:
    DerivedController() {
        static Populate populate_;
    }
    void * print() { return NULL; }
    void * printView() {
        std::cout<<"Print view!"<<std::endl;
        return NULL;
    }
};

上記のコードのデモを見ることができます。

ポピュレーションを半自動にしたい場合でも、メソッドのリストをどこかで定義する必要があります。それらをファイルにリストすることができます。

// DerivedController rules
DERIVED_RULE_INC(print)
DERIVED_RULE_INC(printView)
//...

次に、DerivedControllerこのファイルを使用するようにクラスを変更します。

class DerivedController : public BS_Proxy<DerivedController> {
    struct Populate {
        Populate () {
            #define DERIVED_RULE_INC(x) REG_RULE(DerivedController, x);
            #include "derived_controller_rules.inc"
            #undef DERIVED_RULE_INC
        }
    };
public:
    DerivedController() {
        static Populate populate_;
    }
    #define DERIVED_RULE_INC(x) void * x ();
    #include "derived_controller_rules.inc"
    #undef DERIVED_RULE_INC
};

void * DerivedController::print() { return NULL; }

void * DerivedController::printView() {
    std::cout<<"Print view!"<<std::endl;
    return NULL;
}

これで、ファイルに別のルールを追加すると、登録コードとメソッド宣言が自動的に行われます。ただし、メソッドの定義を実装する必要があります。そうしないと、欠落しているメソッド定義についてリンカーエラーが生成されます。

于 2012-08-11T09:52:11.627 に答える