Как сохранить методы как указатели на функции в контейнере карты? - PullRequest
0 голосов
/ 16 ноября 2018

Я хочу иметь возможность вызывать функции на основе данных, которые я читаю из файла. Поэтому для каждого типа элемента я хочу вызвать нужный метод чтения. Я написал этот код, но он не компилируется там, где я хочу добавить указатели функций на карту. Что случилось?

#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)();
  }



};

Я заполняю карту в Конструкторе.

Ответы [ 4 ]

0 голосов
/ 17 ноября 2018

Я закончил с этим решением. Это делает работу, но у меня есть некоторые сомнения по поводу его эстетики. В любом случае, чтобы подвести итог, я получил следующий код:

#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();
}

Я передаю имя таблицы читателю, это хорошо делается с помощью bind и placeholder .

0 голосов
/ 16 ноября 2018

Вы можете использовать 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"]();
    }
};
0 голосов
/ 16 ноября 2018

Пока есть два ответа: это и это .

Очевидное отличие состоит в том, что один использует std::function, а другие используют указатели на функции.Это не главное различие !!

Ключевым моментом является то, что функции-члены нестатические функции-члены .Таким образом, они не типа void().

Они имеют тип void(reader::*)().Таким образом, они могут быть вызваны, только если задан объект типа читатель;это можно понять как скрытый параметр.

Первый ответ просто решает проблему, указав правильный тип.Это можно сделать с помощью указателей функций (как показано) или с использованием std::function (последнее намного дороже!).

Второй ответ устраняет проблему привязка указатель функции на конкретный экземпляр класса.После связывания тип действительно void().Это нельзя сделать с помощью необработанных указателей на функции (поскольку они могут указывать только на функцию, а не на пару объект / функция!).

0 голосов
/ 16 ноября 2018

Вам нужно использовать указатели на функции-члены, например:

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();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...