So I am unsure why this wont work, ive tried some googling, i just cant find out what the problem is
void Player::Cmd(std::vector<std::string> &tokens)
{
std::string str = tokens[0];
std::map<std::string, void (Player::*)()>::iterator it = playerCommands.find(str);
Func fun;
if (it != playerCommands.end())
{
fun = it->second; //i tried it->second(); same issue
fun(); //error C2064: term does not evaluate to a
//function taking 0 arguments
}
else
{
std::cout << "What? \n";
}
}
git hub for the project
https://github.com/lordkuragari/TextRPG
Contrary to your belief, your map doesn't hold function pointers. So you cannot call the elements in the map.
Rather, your map contains pointers to member functions. Non-static member functions aren't functions and cannot be called; rather, they have to be invoked on an object. You can invoke a member function on an object given by a pointer p via a function pointer ptfm like this:
(p->*ptmf)();
In your case, presumably you want to use p = this and ptfm = fun, so it'd be:
(this->*fun)();
Or, without the local variable:
(this->*it->second)();
In C++17 you can also use std::invoke(it->second, this).
Related
I wonder how to get access to element of list that contains pointers to objects. I want to achieve that without dereferencing. Propably it will be much easier if i just show what i want. So I have list:
list<ObjectClass*> nameOfObject;
and I have method:
bool collision(list<ObjectClass*>::iterator&);
And inside definition of that method I have:
{
if((*nameOfObject)->getSprite()) return true;
else return false;
}
What i want is to getSprite without needing to dereference nameOfObject inside method, so something like that:
{
if((nameOfObject)->getSprite()) return true;
else return false;
}
Everything that i tried is not working. I thought that it would be easy but i really don;t get it. Any ideas? I will add that list has to contain pointer to the objects, because of polimorphysm.
list<ObjectClass*>::iterator&
It's unclear why iterator is passed by reference.
*nameOfObject
This is ill-formed because std::list doesn't have indirection operator. I suspect that you may have shadowed that variable, and forgotten to include the shadowing variable in the example.
What i want is to getSprite without needing to dereference nameOfObject inside method,
Then you need to have an instance of a class with getSprite member function in the class rather than a pointer/iterator to such. If you do have a pointer/iterator, then there is no way to access the pointed object through the pointer without indirection.
so something like that:
(nameOfObject)->getSprite()
That does dereference nameOfObject. -> is the indirecting member access operator. It is also ill-formed with a list.
Any ideas?
Avoid wanting impossible things ¯\_(ツ)_/¯
You usually don't pass single iterator around.
If you want single object, pass single object (whether by reference or pointer)
I write an example code, hope it helps.
fIter is probably what most close to what you currently have
f is demonstrate you can iterate collection without directly use iterator
//
// https://stackoverflow.com/q/63156916/5980430
//
#include <list>
#include <iostream>
class ObjectClass{
public:
int spriteID;
int getSprite(){return spriteID;}
};
//your *collision* function
void collision(ObjectClass& obj){
std::cout << obj.getSprite() << '\n';
}
void f(std::list<ObjectClass>& objs){
for (auto& obj : objs){
collision(obj);
}
}
//even with iterator, you dereference it before pass in other functions
void fIter(std::list<ObjectClass>& objs){
for (auto it = objs.begin(); it != objs.end(); ++it){
collision(*it);
}
}
int main(){
std::list<ObjectClass> objects;
objects.push_back({1});
objects.push_back({2});
objects.push_back({3});
f(objects);
fIter(objects);
}
https://wandbox.org/permlink/SgI5ibjaIXd644DH
I have this pre-defined function.
void attack(std::vector<GameObject*> objects, unsigned damage) {
for (GameObject* object : objects) {
object->takeDamage(damage);
auto isDead = object->isDead();
objects.erase(std::remove_if(objects.begin(),objects.end(),isDead), objects.end());
}
}
This is my isDead function
bool isDead() const {
if (destructed) {
std::cout << "memory error" << std::endl;
}
return life <= 0;
}
This is the error I keep getting. Have tried a lot of things, but not at all able to figure this one out. Any help appreciated!
error: expression cannot be used as a function
{ return bool(_M_pred(*__it)); }
isDead is a variable in the function. You can't use it as an argument to remove_if.
You can't use a regular member function as argument to std::remove_if either. Use a lambda function instead.
Don't erase objects from a container while you are iterating over it using a range for loop.
Change the argument to attack to be a reference. Otherwise, you will be removing objects from a copy, not the original container.
Here's an updated version of attack:
void attack(std::vector<GameObject*>& objects, unsigned damage)
{
for (GameObject* object : objects)
{
object->takeDamage(damage);
}
objects.erase(std::remove_if(objects.begin(),objects.end(), [](GameObject* object){return object->isDead();}), objects.end());
}
isDead() is a member function of one of your classes, which is exactly why it doesn't work: you did not supply this pointer (object instance) for it to be called on. Oh, and the predicate for remove_if must have exactly one argument of the type objects::value_type.
Do this instead:
objects.erase(std::remove_if(objects.begin(),objects.end(),[](GameObject* object){return object->isDead()), objects.end());
I'm having a small problem which I can't wrap my head around.
I have a function that looks like this:
template <typename T>
std::unique_ptr<Environment>& CreateEnvironment(sf::Vector2f& _position, bool _addToStatic = false);
This is my function pointer typedef
typedef std::unique_ptr<Environment>& (WorldEditor::*CreateEnvironmentPtr)(sf::Vector2f&, bool);
std::map<std::string,CreateEnvironmentPtr> listEnv;
And I'm trying to simply do this:
listEnv["test"] = &CreateEnvironment<Coin>(sf::Vector2f(200,200), false);
And i get the following error:
error C2440: '=' : cannot convert from 'std::unique_ptr<_Ty> *' to
'std::unique_ptr<_Ty> &(__thiscall WorldEditor::* )(sf::Vector2f
&,bool)'
I understand what the error is saying, but I don't know how to solve it. Also why does it even care about the return type when I'm pointing to the address of the function?
Best regards
nilo
problems such as these are often much better solved with std::function
std::map<std::string, std::function<void()> listEnv;
listEnv.emplace("test", [] {
CreateEnvironment<Coin>(sf::Vector2f(200,200), false);
});
to call:
listEnv.at("test")->second();
Based on your post I am not sure if you are attempting to create the member function pointer and map inside the CreateEnvironment class or outside of it, so I'll solve what I think is the more difficult problem of pointer to a separate object's member function.
I simplified your classes like so:
Environment
struct Environment
{
int i = 1;
};
Coin
struct Coin
{
int k = 0;
};
WorldEditor
struct WorldEditor
{
template <typename T>
std::unique_ptr<Environment> CreateEnvironment(int& _j, bool _addToStatic = false)
{
return std::make_unique<Environment>();
}
};
Solution: Map an object's member fn pointer, and then call it later
(I will be using C++11/14 syntax in my answer)
//declare a pointer to member function in WorldEditor
using CreateEnvironmentPtr = std::unique_ptr<Environment> (WorldEditor::*)(int&, bool);
//declare an object of type WorldEditor, because member function pointers need a "this" pointer
WorldEditor myWorldEditor;
int myInt = 42;
//map a string to the CreateEnvironment<Coin> function
std::map<std::string, CreateEnvironmentPtr> listEnv;
listEnv["test"] = &WorldEditor::CreateEnvironment<Coin>;
// call the member function pointer using the instance I created, as well as
// the mapped function
(myWorldEditor.*listEnv["test"])(myInt, false);
// (printing member value to cout to show it worked)
std::cout << (myWorldEditor.*listEnv["test"])(myInt, false)->i << std::endl; // prints 1
Live Demo
Solution 2: use std::bind and std::function
Perhaps we already know the parameters to the member function call at the time we create the entry for map. Using std::bind with a std::function will help us achieve that (Similar to Richard Hodges' solution):
// now our "function pointer" is really just a std::function that takes no arguments
using CreateEnvironmentPtr = std::function<std::unique_ptr<Environment>(void)>;
//declare an object of type WorldEditor, because member function pointers need a "this" pointer
WorldEditor myWorldEditor;
int myInt = 42;
//map a string to that function pointer
//ensure it gets called with the right args
// by using std::bind (which will also make the arg list appear the be void at call time)
// note that std::bind needs an instance of the class immediately after
// listing the function it should be binding
// only afterwards will we then pass the int& and bool
std::map<std::string, CreateEnvironmentPtr> listEnv;
listEnv["test"] = std::bind(&WorldEditor::CreateEnvironment<Coin>, &myWorldEditor, myInt, false);
// the mapped function
listEnv["test"]()->i;
// (printing resulting unique_ptr<Environment>'s member to cout to show it worked)
std::cout << listEnv["test"]()->i << std::endl; // prints 1
Live Demo 2
Im trying to remove pairs from vector with remove_if, but im getting errors
bool MyClass::isSingleTag(const pair<int,string> & val) {
string tag = val.second;
int posImg, posBr;
posImg = tag.find("<img");
posBr = tag.find("<br");
if (posImg == -1 && posBr == -1) {
return false;
} else {
return true;
}
}
void MyClass::deleteSingleTags() {
vector<pair<int,string>>::iterator last_iter;
last_iter = remove_if(allTags.begin(), allTags.end(), &MyClass::isSingleTag);
allTags.erase(last_iter, allTags.end());
}
Errors: http://pastebin.com/1FCWRVDG
A pointer to a member function isn't callable without an object of the class the function is member of.
Make isSingleTag static - taking its address results in a plain function pointer. Alternatively, make it a free function, since it looks like it's got no bussiness being a member function in the first place (it doesn't access any other members, does it?).
The other option (for when you legitimately need to be a member function) is to bind it to a class object, using std::bind:
MyClass obj;
auto func = std::bind(&MyClass::isSingleTag, obj);
Now func is a callable that you can pass to the algorithm.
I'm working on a Visual C++ 2010 Express console application.
Before I go into detail, the summary here is: How can I make an array/list/vector of functions and call them from that array?
So I'm having a little difficulty with function pointers. I'm writing a 'Terminal' class, which in turn has a member class 'CommandMap'. The purpose of the CommandMap class is to store a vector/array of functions and the strings that represent them in another vector/array. I want the functions to be called (only) when the class calls them from the vector, but it executed only when I added it to the vector and not when trying to call it.
I tried defining a type for it:
typedef void (*CmdCallback)();
I declared a vector to contain them:
vector<string> CmdNames;
vector<CmdCallback> CmdFuncs;
I add them like so:
// Map a new command
bool CommandMap::Map(string name, CmdCallback func)
{
if (!IsNullOrSpace(name) && func != NULL)
{
if (!Exists(name))
{
CmdNames.push_back(name);
CmdFuncs.push_back(func);
return true;
}
}
return false;
}
And I try calling them like this:
// Get a command callback from its identifier
CmdCallback CommandMap::GetFunc(string name)
{
int index = IndexOf(name);
if (index == -1) return NULL;
else return CmdFuncs.at(index);
}
// If the given string is a command indentifier
// it will invoke the associated callback.
bool CommandMap::Exec(string input)
{
for each (string id in CmdStrings)
{
if (input == id)
{
CmdCallback cmd;
cmd = GetFunc(id);
cmd();
return true;
}
}
return false;
}
I tried using this:
CmdCallback SayHello()
{
cout << "Hello World!" << endl;
return NULL; // Forces me to return null, guessing since it's
// not 'void' but a 'void' pointer it must return something
}
int main(int argc, char *argv[])
{
App = new Terminal(argc, argv);
App->Commands->Map("say", SayHello);
while (!App->ExecComplete)
{
App->WaitEnter();
App->Commands->Exec("say");
App->WaitEnter();
App->ExecComplete = true;
}
return App->ExitCode;
}
This works, at first. The function gets called when I try to Map() it though. And when I Exec() "say", it finds the callback, but when it tries to call it, I get this runtime error, to which I can see no detail other than the option to break or continue. The code it gives me is.
I pretty much want to abandon my method and try a new approach, maybe I'm going the wrong way with the void pointer typedef, and I need to throw a '&' or a '*' somewhere I haven't like in the Map() argument list. Maybe a vector isn't the best way to do this either.
Basically, I am asking how I can I make an array of functions that can (and only) be called by referencing them from the array. I'm terrible with callbacks.
You can use std::functions, or, if you don't have C++11 support, boost::function. These are function object wrappers that can be easily constructed from free or member functions. You can store these in a standard library container or simple array.
If I understand correctly you actually want to declare SayHello as void SayHello() so that a pointer to SayHello has the type void (*)() (i.e. CmdCallback) which is what you need for your vector of functions.