c ++ std :: карта разнородных указателей на функции - PullRequest
2 голосов
/ 21 октября 2011

Можно ли хранить указатели на различные гетерогенные функции, такие как:

В заголовке:

int  functionA (int param1);
void functionB (void);

В основном это будет часть, которую я не знаю, как написать:


typedef ??boost::function<void(void)>?? functionPointer;

И потом:

map<char*,functionPointer> _myMap;

В .cpp

void CreateFunctionMap()
{
    _myMap["functionA"] = &functionA;
    _myMap["functionB"] = &functionB;
    ...
}

И затем использовать его как:

void execute(int argc, char* argv[])
{

    if(argc>1){
        int param = atoi(argv[1]);
        int answer;
        functionPointer mfp;
        mfp = map[argv[0]];
        answer = *mfp(param);
    }
    else{
        *map[argv[0]];
    }
}

и т. Д.

Спасибо

- РЕДАКТИРОВАТЬ -

Просто чтобы дать больше информации:

ПричинаЭтот вопрос заключается в том, что я реализую раскрывающуюся консоль в стиле quake для уже существующего приложения.Таким образом, я могу обеспечить пользовательский ввод во время выполнения командной строки для доступа к различным уже кодированным функциям различных типов, например:

 /exec <functionName> <param1> <param2> ...

Ответы [ 5 ]

3 голосов
/ 21 октября 2011

Вы можете использовать

boost::variant<
    boost::function<void(void)>,
    boost::function<void(int)> >
3 голосов
/ 21 октября 2011

Если вы хотите иметь «указатель на что-то, но я не собираюсь определять что, и это может быть множество вещей», вы можете использовать void *.

Но вы действительно не должны't.

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

EDIT

Чтобы дать вам более полезный ответ, нет необходимости помещать все это в одну карту.Можно использовать несколько карт.Т.е.

typedef boost::function<void(void)> voidFunctionPointer;
typedef boost::function<int(int)>   intFunctionPointer;

map<std::string, voidFunctionPointer> _myVoidMap;
map<std::string, intFunctionPointer > _myIntMap;

void CreateFunctionMap()
{
  _myVoidMap["functionA"] = &functionA;
  _myIntMap["functionB"] = &functionB;
  ...
}

void execute(int argc, char* argv[])
{

  if(argc>1){
    int param = atoi(argv[1]);
    int answer;
    // todo: check that argv[0] is actually in the map
    intFunctionPointer mfp = _myIntMap[argv[0]];
    answer = mfp(param);
  }
  else{
    // todo: check that argv[0] is actually in the map
    voidFunctionPointer mfp = _myVoidMap[argv[0]];
    mfp();
  }
}
2 голосов
/ 21 октября 2011

Не можете ли вы использовать шаблон команды для инкапсуляции вызовов функций. Таким образом, вы можете хранить функции в функторах и вызывать их после вардов. Для реализации функтора вы можете взглянуть на Modern C ++ Design Андрея Александреску.

2 голосов
/ 21 октября 2011

Почему бы просто не добавить функции типа int (*func)(int argc, char* argv[])? Вы можете легко удалить первый аргумент из параметров execute и вызвать соответствующий.

1 голос
/ 21 октября 2011

Каждая из ваших функций имеет свой тип, так что вам нужно какое-то стирание типа. Вы можете использовать самый общий из них: Boost.Any. Вы можете иметь map из boost::any, но вам нужно знать тип функции, чтобы вернуть ее и вызвать.

В качестве альтернативы, если вы заранее знаете свои аргументы, вы можете bind их вызвать с помощью вызова функции, и все функции на карте будут нулевыми функциями: function< void() >. Даже если вы этого не сделаете, вы можете обойтись без него, связав аргумент со ссылками, а затем во время вызова заполните указанные переменные соответствующими аргументами.

...