Сборка и выполнение стека пустых функций - PullRequest
4 голосов
/ 29 июня 2011

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

Так что мои функции всегда будут иметь тип void. Моя проблема / недоразумение заключается в том, как исключить stl :: стек пустых функций и как мне выполнить эту функцию?

class InstructionScreen
{

  std::stack <void*> instructionSteps;  // is this how I declare a stack of functions

  void runTimerEvent()
  {
      if ( !instructionSteps.empty() ) 
      {
          // call the function at the top of the stack
          // how do I call the function?
          (*instructionSteps.top()); // is that how?
          instructionSteps.pop();
      }
  }

  void step1()
  {
     // here I create some widgets & add them to the main window
  }

  void step2()
  {
     // delete widgets from window
     // create some different widgets & add them to the main window
  }

  void buildStack()
  {
     instructionSteps.push( (&step1()) ); // is this correct?
     instructionSteps.push( (&step2()) );  
  }

};

Ответы [ 6 ]

3 голосов
/ 29 июня 2011

A void* указатель не является допустимым указателем на функцию.Это должно быть void (*)(), что можно сделать лучше с помощью typedef void (*stack_function)().

std::stack<stack_function> instructionSteps;

Чтобы вставить что-то в это, вы не вызываете функцию (как вы делаете с step1()) ивы, конечно, не берете адрес возврата (который в любом случае является недействительным), как вы делаете с &step1(), вы просто используете одно только имя функции:

instructionSteps.push(step1); // the & can be omitted for free functions
instructionSteps.push(&step2); // equivalent to the above, only a different function

Для вызова вещи с вершиныстек, вам на самом деле нужно сделать вызов:

(*instructionSteps.top())();
//    you missed that -- ^^

Разыменование может быть также опущено по причинам, которые здесь могут объясняться слишком долго, ищите SO.:)

instructionSteps.top()();
2 голосов
/ 29 июня 2011

Синтаксис для статического указателя на функцию выглядит следующим образом:

void (*FuncPtr)();

Для указателя члена вы должны использовать этот синтаксис:

void (class::*FuncPtr)();

Если ваши функции не требуютфункции быть членами функции намного чище.Как только вы выяснили, какие функции вам нужны, проще всего определить эти функции следующим образом:

typedef void(*FuncPtrType)();
typedef void(Class::*MemberFuncPtrType)();

Теперь вы можете просто объявить стек с указателями на функции, например:

std::stack <FuncPtrType> funcPtrStack;
std::stack <MemberFuncPtrType> memberFuncPtrStack;

Чтобы получить указатель на функцию, вы просто используете оператор «&», как если бы вы получали адрес для любого другого типа данных в C ++:

FuncPtrType funcPtr = &staticFunc; // Somewhere "void staticFunc()" is defined
MemberFuncPtrType memberFuncPtr = &Class::MemberFunc; // Somewhere void "Class::MemberFunc()" is defined

Чтобы фактически вызывать указатели на функции, вы должны использоватьОператор «*» для возврата данных из указателя (как и любой другой тип данных в C ++).Единственная хитрость в том, что для функций-членов им нужен указатель на класс, что делает его очень неудобным в использовании.Вот почему я рекомендовал использовать статические функции для начала.В любом случае, вот синтаксис:

(*funcPtr)(); // I just called a function with a pointer!
(this->*memberFuncPtr)(); // I just wrote some ugly code to call a member function

Показав все это, теперь должен иметь смысл следующий код:

std::stack <MemberFuncPtrType> memberFuncPtrStack; // Declaring the stack
memberFuncPtrStack.push( &Class::MemberFunc ); // Pushing a function
(ClassPtr->*memberFuncPtrStack.top())(); // Calling the function with ClassPtr
1 голос
/ 29 июня 2011

Совет: используйте Boost.Function, это намного проще.Он будет хранить не только функции с правильным типом, но и все остальное, что можно вызывать таким же образом.

std::stack<boost::function<void()> instructionSteps;
int foo() { return 42; }
instructionSteps.push(foo); // Close enough - return value will be discarded.
1 голос
/ 29 июня 2011

Объявите typedef и сделайте из него vector / stack:

typedef void (*funcptr)();
std::stack<funcptr> instructionSteps;

Использование:

instructionSteps.push(&step1);
instructionSteps.push(&step2);  

См. Демоверсию здесь . Исполнение:

instructionSteps.top()();
0 голосов
/ 29 июня 2011

Я бы typedef указатель функции, чтобы сделать вашу жизнь проще:

typedef void(*voidFunctionPointer)(); // Assuming here that the functions take no arguments.

std::stack<voidFunctionPointer> instructionSteps; // This is very different from <void*>.  
                                                  // The latter is merely a stack of void pointers.

Один из способов вызова верхней функции - это:

voidFunctionPointer functionToCall = instructionSteps.top();
functionToCall();

Если вы хотите сделать это без дополнительной декларации, я думаю, это должно сработать. Пожалуйста, поправьте меня, если я ошибаюсь.

instructionSteps.top()();

Чтобы построить стек, просто используйте имя функции без завершающих скобок.

instructionSteps.push(step1);
instructionSteps.push(step2);
// ...
0 голосов
/ 29 июня 2011
typedef void (*fptr)();
class InstructionScreen
{

  std::stack <fptr> instructionSteps; 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...