2012-01-26 42 views
1

コードをC++のメンバー関数にマップするテーブルが必要です。私たちは、このクラスがあるとします。私はfooオブジェクトfを持っている場合、f.call(”somestring”)は表に「somestring」を見上げるなるように、C++のメンバー関数のテーブル

{ 
    { “somestring”, one }, 
    { ”otherstring”, two } 
}; 

:私が欲しいもの

class foo 
{ 
    bool one() const; 
    bool two() const; 
    bool call(char*) const; 
}; 

は、このようなテーブルですone()メンバ関数を呼び出して、結果を返します。

呼び出される関数はすべて同じプロトタイプを持ちます。つまり、const、パラメータなし、およびboolを返します。

これは可能ですか?どうやって?

+0

これはすべて非常に手作業です。より興味深いのは、自動的に行うための最良の方法です。 – Dan

答えて

2

あなただけの同じ引数で、同じクラスのメンバーを格納し、型を返す、あなたはポインタ・ツー・メンバー関数を使用することができますする必要がありますので:

bool foo::call(char const * name) const { 
    static std::map<std::string, bool (foo::*)() const> table 
    { 
     {"one", &foo::one}, 
     {"two", &foo::two} 
    }; 

    auto entry = table.find(name); 
    if (entry != table.end()) { 
     return (this->*(entry->second))(); 
    } else { 
     return false; 
    } 
} 

Cの新しい初期化構文を使用しています++ 11。あなたのコンパイラがそれをサポートしていない場合は、さまざまなオプションがあります。

typedef std::map<std::string, bool (foo::*)() const> table_type; 
static table_type table = make_table(); 

static table_type make_table() { 
    table_type table; 
    table["one"] = &foo::one; 
    table["two"] = &foo::two; 
    return table; 
} 

か、Boost.Assignment使用できます:あなたは、静的な機能とマップを初期化することができ

static std::map<std::string, bool (foo::*)() const> table = 
    boost::assign::map_list_of 
     ("one", &foo::one) 
     ("two", &foo::two); 

をしたり、配列を使用することができ、およびstd::find_ifを持つエントリ(または単純forループの場合を見つけますあなたのライブラリにはそれがまだありません)、または配列がソートされていることを確認する場合はstd::binary_searchです。

+1

+1は 'auto'を使用します。さもなければ、std :: map Nawaz

+1

私はこのメソッドの優雅さとシンプルさが気に入っていますが、そのような 'map'を初期化することはできないと思いましたか?とにかく、MSVCはそれを好きではありません。 – chrisd

+0

@chrisd:それは新しいC++ 11の初期化構文です。コンパイラがそれをサポートしていない場合は、いくつかの選択肢を追加しました。 –

3

はい。

struct foo_method 
{ 
    std::string name; 
    bool (foo::*pfun)() const; 
}; 

foo_method methodTable[] = 
{ 
    { “somestring”, &foo::one }, 
    { ”otherstring”, &foo::one } 
}; 

void foo::call(const char* name) const 
{ 
    size_t size = sizeof(methodTable)/sizeof(*methodTable); 
    for(size_t i = 0 ; i < size ; ++i) 
    { 
     if (methodTable[i].name == name) 
     { 
      bool (foo::*pfun)() const = methodTable[i].pfun; 
      (this->*pfun)(); //invoke 
     } 
    } 
} 
+1

私はテーブルへのマップを好むと思いますが、そのアイデアは有効です。 –

6

はい、それはメンバー構文にポインタを使用して、可能です。

指定したプロトタイプを使用すると、マップは次のようになります。

std::map< std::string, bool(foo::*)() const> 

それはこの構文奇妙->*オペレータは、継承のためにいくつかの奇妙な配慮を持つことができるメンバ関数へのポインタです

this->*my_map["somestring"](); 

で呼び出されます。 ->が期待しているのは生の住所だけではありません。

+0

@MooingDuck:ありがとう。私はそれを見落とした。 –

2

私はboost::functionstd::mapで行きます。具体的には、このような何か:

typedef boost::function<bool()> MyFunc; 
typedef std::map<std::string, MyFunc> MyFuncMap; 

はその後、MyFuncMapのインスタンス与えられた、あなただけのmap["something"]()を行うことができます。次に、それをオーバーロードするクラスでラップすることができますoperator()。関数ポインタ/参照を使用することができますが、私はboost::functionを使用することをお勧めします。これは、(boost :: bindを使用して)メンバ関数へのポインタをバインドするか、他の関数オブジェクトを使用できるからです。通常の関数ポインタの場合と同様に、条件の中でboost::functionをテストすることもできます。

幸運:ここ

は、関連するドキュメントです!

編集:constメンバとboost::functionに関するご質問については、ここでの例です:

#include <boost/function.hpp> 
#include <boost/bind.hpp> 

typedef boost::function<bool()> FuncPtr; 

struct Test 
{ 
    bool test() const 
    { 
     std::cout << "yay" << std::endl; 
    } 
}; 

int main(int argc, char **argv) 
{ 
    Test t; 
    FuncPtr ptr = boost::bind(&Test::test, &t); 
    ptr(); 
} 
+0

'const'は関数の型の一部ですが、' boost :: function'とどうやって相互作用するのか分かりません。それが宣言の一部であるべきか? –

+0

これを調べたところ、 'boost :: function 'はconstメンバーとnon-constメンバーの両方で動作するようです。どのように、なぜ、それは動作するのかは分かりませんが、動作します。 – migimunz

1
私はクラスのインスタンスを持つことなく、メンバ関数へのポインタが無意味であることを追加したい

それを呼び出すことができます。あなたがこれを説明している状況(そしてこれはあなたがこれを知っていると思う)だが、他の状況では、関数ポインタをポインタで参照するか、それが対応するインスタンスへの参照をカプセル化する必要があるかもしれない。functor

関連する問題