Как сопоставить строку с функцией в Visual Studio 2008? - PullRequest
3 голосов
/ 09 января 2020

Этот вопрос относится к следующему заданному вопросу: Использование STL-карты указателей функций

В C ++ 11 я использую карту для хранения пары <string, function> для более эффективно выполнять код вместо использования if...else if...else if, как указано в ссылочной ссылке.

Код инкапсулирован в функцию-член, где this относится к классу, что позволяет получить доступ к переменным-членам.

using f = std::function<void()>;
static const std::map<std::string, f> doSumthin{
  {"case 1", [this]() {
    // execute code in case 1
  }},
  {"case 2", [this]() {
   // execute code in case 2
  }},
  …
};

auto it = doSumthin.find(someString);

if (it != doSumthin.end())
{
    it->second();
}

Однако мне нужно, чтобы базовая часть кода работала в VS 2008. Я не уверен, какой самый оптимальный способ добиться репликации вышеуказанного кода для работы в VS 2008, не возвращаясь к менее эффективному if...else if .

Могу ли я получить некоторые рекомендации по этому вопросу?

Ответы [ 2 ]

4 голосов
/ 09 января 2020
#include <map>
#include <string>

typedef void (*func_ptr_type)();

void func_case_1() {}
void func_case_2() {}

static std::map<std::string, func_ptr_type> doSumthin;

void initMap()
{
    doSumthin["case 1"] = func_case_1;
    doSumthin["case 2"] = func_case_2;
}

int main()
{
    initMap();

    std::map<std::string, func_ptr_type>::iterator it = doSumthin.find("case 1");
    if (it != doSumthin.end())
    {
        it->second();
    }
    return 0;
}

2 голосов
/ 09 января 2020

Я специально не тестировал это на VS2008, но я уверен, что это действительно C ++ 98.

#include <map>
#include <string>

class Foo {
  void case_1() {}
  void case_2() {}

  typedef std::map<std::string, void(Foo::*)()> CaseMap; 

  static CaseMap initCases() {
    CaseMap cases;
    cases["case_1"] = &Foo::case_1;
    cases["case_2"] = &Foo::case_2;
    return cases;
  }

  static const CaseMap cases;

public:
  void execute(const std::string &name) {
    CaseMap::const_iterator iter = cases.find(name);
    if (iter != cases.end()) {
      void(Foo::*func)() = iter->second;
      (this->*func)();
    }
  }
};

const Foo::CaseMap Foo::cases = Foo::initCases();

Другая возможность - использовать X-макросы. Я считаю, что это как можно ближе к фрагменту C ++ 11 (но я бы не рекомендовал его использовать).

#define CASES(X)        \
  X(case_1, {           \
    /* do case 1 */     \
  })                    \
  X(case_2, {           \
    /* do case 2 */     \
  })

#define DEFINE_FUNCTION(NAME, CODE) void NAME() CODE
#define INIT_MAP(NAME, CODE) cases[#NAME] = &Bar::NAME;

class Bar {
  CASES(DEFINE_FUNCTION)

  typedef std::map<std::string, void(Bar::*)()> CaseMap;

  static CaseMap initCases() {
    CaseMap cases;
    CASES(INIT_MAP)
    return cases;
  }

  static const CaseMap cases;

public:
  void execute(const std::string &name) {
    CaseMap::const_iterator iter = cases.find(name);
    if (iter != cases.end()) {
      void(Bar::*func)() = iter->second;
      (this->*func)();
    }
  }
};

const Bar::CaseMap Bar::cases = Bar::initCases();
...