I'm trying to write an application that adds function pointers to a vector based on some external event, then iterates through the list. For some reason, I can't seem to get the functions to actually execute despite the fact that they are added to the vector.
What am I missing?
main.cpp
#include "GameLogic.h"
GameLogic* gameLogic = nullptr;
int main(int argc, char* argv[])
{
gameLogic = new GameLogic();
gameLogic->run();
}
GameLogic.cpp
#include "GameLogic.h"
GameLogic::GameLogic()
{
FireAction.push_back(&GameLogic::AddCredit);
FireAction.push_back(&GameLogic::AddPlayer);
}
GameLogic::~GameLogic() {}
void GameLogic::run()
{
for (std::vector<std::function<void(const GameLogic)>>::iterator it = FireAction.begin(); it != FireAction.end(); it++)
{
std::cout << "Iterator Loop" << std::endl;
(*it);
}
}
void GameLogic::AddCredit() { std::cout << "Added Credit" << std::endl; }
void GameLogic::AddPlayer() { std::cout << "Added Player" << std::endl; }
GameLogic.h
#pragma once
#include <functional>
#include <iostream>
#include <vector>
class GameLogic
{
public:
GameLogic();
~GameLogic();
void run();
private:
void AddCredit();
void AddPlayer();
std::vector<std::function<void(const GameLogic)>> FireAction;
};
Execution Output:
Iterator Loop
Iterator Loop
Expected Output:
Iterator Loop
Added Credit
Iterator Loop
Added Player
You are dereferencing the vector iterators to access the stored std::function
objects, but you are not actually calling their operator()
to execute your class methods. You need to add an extra set of parenthesis for those calls, eg:
(*it)(*this);
This is made clearer if you store the std::function
s to a local variable before calling them, eg:
std::function<void(const GameLogic)> &func = *it;
// better: auto &func = *it;
func(*this);
Now, that being said, your std::function
objects need to take your GameLogic
object by pointer or reference, instead of by value, eg:
std::vector<std::function<void(const GameLogic&)>> FireAction;
...
(*it)(*this);
// or:
// auto &func = *it;
// func(*this);
Or:
std::vector<std::function<void(const GameLogic*)>> FireAction;
...
(*it)(this);
// or:
// auto &func = *it;
// func(this);
You can avoid this requirement by storing lambdas instead of pointer-to-member's, so you don't have to pass around the GameLogic
object explicitly:
std::vector<std::function<void()>> FireAction;
...
FireAction.push_back([this](){ this->AddCredit(); });
FireAction.push_back([this](){ this->AddPlayer(); });
...
(*it)();
// or:
// auto &func = *it;
// func();
Lastly, to simply the code even further, consider using auto
(as seen above) and range-based for loops, eg:
void GameLogic::run()
{
for (auto it = FireAction.begin(); it != FireAction.end(); ++it)
{
std::cout << "Iterator Loop" << std::endl;
(*it)();
// or:
// auto &func = *it;
// func();
}
}
Or:
void GameLogic::run()
{
for (auto &func : FireAction)
{
std::cout << "Iterator Loop" << std::endl;
func();
}
}
If you expect (*it)
to call a function pointer, you're mistaken.
You should write: (*it)(...parameters...)
instead, that will get you closer. The parameter needs to be the GameLogic
object that you expect those member functions to be called upon.
Note: your std::function<void(const GameLogic)>
should probably be std::function<void(const GameLogic &)>
or std::function<void(GameLogic &)>
unless you like making copies of things.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.