web-dev-qa-db-ja.com

メソッドを関数ポインターとしてマップコンテナーに格納する方法は?

ファイルから読み取ったデータに基づいて関数を呼び出せるようにしたい。そのため、アイテムの種類ごとに、目的のリーダーメソッドを呼び出します。このコードを書きましたが、関数ポインターをマップに追加する場所をコンパイルしません。なにが問題ですか?

#include <vector>
#include <map>
#include <iostream>
class reader
{

  std::map< std::string, void(*)()> functionCallMap; // function pointer
  void readA(){ std::cout << "reading A\n";};
  void readB(){ std::cout << "reading B\n";};;
public:
  reader()
  {
    *functionCallMap["A"] = &reader::readA;*
    *functionCallMap["B"] = &reader::readB;*
  }

  void read()
  {
   auto (*f) = functionCallMap["A"];
   (*f)();
  }



};

コンストラクターでマップを埋めています。

17
Ring Zero.

std::functionをラムダまたはstd::bindとともに使用できます。

class reader
{
    std::map<std::string, std::function<void()>> functionCallMap;

    void readA() { std::cout << "reading A\n"; };
    void readB() { std::cout << "reading B\n"; };

public:
    reader()
    {
        functionCallMap["A"] = [this]() { readA(); };
        functionCallMap["B"] = std::bind(&reader::readB, this);
    }

    void read()
    {
        functionCallMap["A"]();
        functionCallMap["B"]();
    }
};
20
Siliace

次のように、メンバー関数へのポインターを使用する必要があります。

class reader
{
    using FuncPtr = void(reader::*)(); // function pointer
    std::map< std::string, FuncPtr> functionCallMap;
    void readA(){ std::cout << "reading A\n"; }
    void readB(){ std::cout << "reading B\n"; }
public:
    reader()
    {
        functionCallMap["A"] = &reader::readA;
        functionCallMap["B"] = &reader::readB;
    }

    void read()
    {
        auto f = functionCallMap["A"];
        (this->*f)();
    }
};

int main()
{
    reader r;
    r.read();
}
17
snake_style

これまでのところ、 thisthis の2つの答えがあります。

明らかな違いは、1つは_std::function_を使用し、もう1つは関数ポインターを使用することです。これは重要な違いではありません!!

重要な点は、メンバー関数が非静的メンバー関数であることです。したがって、これらはnotvoid()型です。

それらはvoid(reader::*)()型です。したがって、タイプのオブジェクトがリーダーである場合にのみ呼び出すことができます。これは、隠されたパラメーターとしてある程度理解できます。

最初の答え は、correctタイプを指定することで問題を修正するだけです。これは、関数ポインター(提示)を使用して行うことができますまたは_std::function_を使用します(後者ははるかに高価です!)。

2番目の答え は、binding関数ポインタをクラスの特定のインスタンス。バインド後、タイプは実際にvoid()になります。未加工の関数ポインタを使用してこれを行うことはできません(オブジェクト/関数のペアではなく関数のみを指すことができるためです!)。

9
Handy999

私はこの解決策になりました。それは仕事をしますが、私はその美学についていくつかの疑問を持っています。とにかく、要約すると、私はこのコードで終わった:

#include <map>
#include <iostream>
#include <functional>
class reader
{
    std::map< std::string, std::function<void(std::string tableName)>> functionCallMap; // function pointer
    void readA(const std::string tableName){ std::cout << "reading:" << tableName<< "\n"; }
    void readB(const std::string tableName){ std::cout << "reading:" << tableName <<"\n"; }
public:
    reader()
    {
      functionCallMap["A"] = std::bind(&reader::readA, this, std::placeholders::_1);
      functionCallMap["B"] = std::bind(&reader::readA, this, std::placeholders::_1);
    }

    void read()
    {
      const std::string table_name = "A";
      functionCallMap[table_name](table_name);
    }
};

int main()
{
    reader r;
    r.read();
}

テーブル名をリーダーに渡します。これはbindplaceholderでうまく行われます。

1
Ring Zero.