8

文字列をインスタンスメンバー関数にマップし、各マッピングをマップに保存したいと思います。

そのようなことをするためのクリーンな方法は何ですか?

class  MyClass
{
   //........
   virtual double GetX();
   virtual double GetSomethingElse();
   virtual double GetT();
   virtual double GetRR();
   //........
};


class Processor
{
 private:
      typedef double (MyClass::*MemFuncGetter)();
      static map<std::string, MemFuncGetter> descrToFuncMap;

 public:
        static void Initialize();
        void Process(Myclass m, string);
};

void Processor::Initialize()
{

     descrToFuncMap["X"]=&MyClass::GetX;
     descrToFuncMap["SomethingElse"]=&MyClass::GetSomethingElse;
     descrToFuncMap["RR"]=&MyClass::GetRR;
     descrToFuncMap["T"]=&MyClass::GetT;
};
void Processor::Process(MyClass ms, const std::string& key)
{
     map<std::string, Getter>::iterator found=descrToFuncMap.find(key);
     if(found!=descrToFuncMap.end())
     {
        MemFuncGetter memFunc=found->second;
        double dResult=(ms).*memFunc();    
        std::cout<<"Command="<<key<<", and result="<<result<<std::end;      
      }
 }  

このアプローチに問題がある場合は、その一般的なイディオムを教えてください。

おそらく、funcポインターの紛らわしいマップではなく、メンバー関数の数が限られていることを考えると、if-else-ifステートメントチェーンを使用する必要があります

ところで、私はここでいくつかの有用な情報をc++-faq-liteで見つけました

4

3 に答える 3

6

私には問題ないように見えますが、静的関数内から初期化する場合descrToFuncMapは宣言する必要があるという事実のために。staticInitialize()

Initialize()が呼び出され、一度だけ呼び出されるようにしたい場合は、Singleton パターンを使用できます。基本的に、マルチスレッドを行っていない場合、それはを呼び出すプライベート コンストラクターを使用してdescrToFuncMap独自のクラス ( say と呼ばれる) 内にラップすることを意味します。次に、タイプのローカル変数を--に追加します。変数はであるため、永続化され、一度だけ初期化されます。FuncMapInitialize()staticFuncMapProcessor::Process()static

サンプルコード (ここでは実際には必要ないことに気付きfriendました):

class Processor {
private:
    typedef double (MyClass::*MemFuncGetter)();

    class FuncMap {
    public:
        FuncMap() {
            descrToFuncMap["X"]=&MyClass::GetX;
            descrToFuncMap["SomethingElse"]=&MyClass::GetSomethingElse;
            descrToFuncMap["RR"]=&MyClass::GetRR;
            descrToFuncMap["T"]=&MyClass::GetT;
        }

        // Of course you could encapsulate this, but its hardly worth
        // the bother since the whole class is private anyway.
        map<std::string, MemFuncGetter> descrToFuncMap;
    };

public:
    void Process(Myclass m, string);
};

void Processor::Process(MyClass ms, const std::string& key) {
    static FuncMap fm;      // Only gets initialised on first call
    map<std::string, Getter>::iterator found=fm.descrToFuncMap.find(key);
    if(found!=fm.descrToFuncMap.end()) {
        MemFuncGetter memFunc=found->second;
        double dResult=(ms).*memFunc();    
        std::cout<<"Command="<<key<<", and result="<<result<<std::end;      
    }
}

さまざまな関数が独自の個別のインスタンスを作成できるため、これは「真の」シングルトンパターンではありませんが、FuncMap必要なものには十分です。FuncMap「真の」シングルトンの場合、のコンストラクターを private と宣言し、静的メソッドを追加します。getInstance()たとえば、 は、唯一無二のインスタンスをstatic変数として定義し、それへの参照を返します。 Processor::Process()次にこれを使用します

FuncMap& fm = FuncMap::getInstance();
于 2009-03-10T16:08:58.690 に答える
0

私は変わるだろう

void Processor::Process(MyClass ms, std::string key)

void Processor::Process(const MyClass& ms, const std::string& key)

今のところ悪い副作用は見られません。おそらく、マップ値として boost::function を使用すると、将来的には簡単になります。

于 2009-03-10T16:03:47.657 に答える
0

関数ポインターのマップを使用している場合は、'virtual' を使用しないでください。このコンテキストでは、「virtual」キーワードを使用してもあまり役に立ちません。例えば

descrToFuncMap["X"]=&MyClass::GetX;

GetXが MyClass の派生クラスによってオーバーライドされた場合でも、常に ' MyClass::GetX ' 関数を呼び出します。

通常、クラスには多数の関数はありません。マップを使用するのではなく、単純な構造体配列を作成して for ループを使用できます。関数の数が少ない場合、マップと配列で大きなパフォーマンスの違いはありません。以下のコードに似たものが機能します

class  MyClass
{
   //........
   double GetX();
   double GetSomethingElse();
   double GetT();
   double GetRR();
   //........
};

typedef double (MyClass::*MemFuncGetter)();

struct FuncTable
{
    const char* m_pFuncName;
    MemFuncGetter m_pFuncPtr;
};

class Processor
{          
 public:
        void Process(Myclass& m, string);
};

static FuncTable descrToFuncMap[]
{
    { "X",  &MyClass::GetX},
    { "SomethingElse", &MyClass::GetSomethingElse },
    { "RR", &MyClass::GetRR},
    { "T", &MyClass::GetT}
};

void Processor::Process(MyClass& ms, const std::string& key)
{
    int functablesize = sizeof(descrToFuncMap)/sizeof(descrToFuncMap[0])

    for(int i=0; i< functablesize; ++i)
    {   
        if( strcmp(key.c_str(), descrToFuncMap[i].m_pFuncName)==0)
        {
            MemFuncGetter memFunc=descrToFuncMap[i].m_pFuncPtr;
            double dResult=(ms).*memFunc();    
            std::cout<<"Command="<<key<<"result="<<result<<std::end;
            break;
        }
    }     
 }
于 2009-03-11T12:23:58.033 に答える