C++ List Iterator cant be initlaized - c++

I have two functions in my Character class:
void Character::dropItem(const Item & item)
{
for (list<const Item*>::iterator i = playerInventory.inventory.begin(); i != playerInventory.inventory.end(); i++) {
if ((*i) == &item) {
playerInventory.inventory.erase(i);
break;
}
}
}
double Character::getTotalWeight() const
{
for (list<const Item*>::iterator i = playerInventory.inventory.begin(); i != playerInventory.inventory.end(); i++) {
}
}
However, Visual Studio gives me an error
Error C2440 'initializing': cannot convert from 'std::_List_const_iterator<std::_List_val<std::_List_simple_types<_Ty>>>' to 'std::_List_iterator<std::_List_val<std::_List_simple_types<_Ty>>>'
on playerInventory in the first statement of the for loop in getTotalWeight().
I can't figure out why this error is occurring, because it's literally the same loop as the function just above it. Any insight is appreciated.

The function is a constant member function
double Character::getTotalWeight() const
So the data member playerInventory.inventory is considered as a constant data member. As a result you may not use a non-constant iterator.
Write instead
for (list<const Item*>::const_iterator i = playerInventory.inventory.cbegin(); i != playerInventory.inventory.cend(); i++) {
That is the member function begin returna const_iterator while you are trying to assign it to iterator and there is no corresponding conversion from the first iterator type to the second iterator type.

Related

Illegal operand error on a function pointer iterator

I am getting the following errors:
'<': illegal, left operand has type 'const_Ty'
'>: illegal, right operand has type 'const_Ty'
in the below code.
It's a relative simple iterator on a function pointer map where the functions are of the form void (Game::*)(UINT). I check the value against a float, then run the function.
The problem seems to be in the for line, although I've got another substantially similar for loop somewhere else that works without a problem.
using FuncPtr = void (Game::*)(UINT);
std::map<FuncPtr, float> funcDelayedTriggerMap;
void Game::PollProcessDelayedTriggers()
{
for (std::map<FuncPtr, float>::iterator it = funcDelayedTriggerMap.begin(); it != funcDelayedTriggerMap.end(); ++it)
{
float currentS = m_timer.GetElapsedSeconds();
if (it->second < currentS)
{
(this->*(it->first))(UINT_MAX);
funcDelayedTriggerMap.erase(it->first);
}
}
}
Member function pointers don't implement operator<, which is the default sorting function std::map uses.
Member function pointers only implement operator== and operator!= .
An easy way to fix this woud be to have a separate key and put the function pointer into the value of the map, e.g.:
std::map<int, std::pair<FuncPtr, float>>
or if you don't need the fast lookup of std::map, a simple vector would also work:
std::vector<std::pair<FuncPtr, float>>
An alternative approach would be to use the function pointer type as key:
using FuncPtr = void (Game::*)(int);
// Just a helper to get a unique type for each function pointer
template<FuncPtr ptr>
struct Tag {};
struct DelayedTrigger {
FuncPtr ptr;
float value;
DelayedTrigger() : ptr(nullptr), value(0.0f) {}
DelayedTrigger(FuncPtr _ptr, float _value) : ptr(_ptr), value(_value) {}
};
std::map<std::type_index, DelayedTrigger> funcDelayedTriggerMap;
void Game::PollProcessDelayedTriggers()
{
for (std::map<std::type_index, DelayedTrigger>::iterator it = funcDelayedTriggerMap.begin(); it != funcDelayedTriggerMap.end(); ++it)
{
float currentS = 1.0;
if (it->second.value < currentS)
{
(this->*(it->second.ptr))(0);
funcDelayedTriggerMap.erase(it->first);
}
}
}
This essentially uses the specific function pointer as a unique key.
You could then add new entries like this:
funcDelayedTriggerMap.emplace(typeid(Tag<&Game::DoIt>), DelayedTrigger{&Game::DoIt, 1.0f});
// or
funcDelayedTriggerMap[typeid(Tag<&Game::DoIt>)] = {&Game::DoIt, 1.0f};
And check if a function is present:
if(funcDelayedTriggerMap.contains(typeid(Tag<&Game::DoIt>))) {
// ...
}
This however only works if you know all the functions you want to use with the map at compile time.

String array to C++ function

I want to check if a given name is inside an array of possible names. I wrote this small debugging function ( yeah... I know it always return true ) trying to understand why it does not work and why I get the below error.
Code
char[] people_names = ["Mario","Luigi"];
bool lookupTerm (string term, string possible_names[]){
for(const string &possible_name : possible_names)
cout << possible_name << endl;
return true;
}
Error
jdoodle.cpp: In function 'bool lookupTerm(std::__cxx11::string, std::__cxx11::string*)':
jdoodle.cpp:19:38: error: no matching function for call to 'begin(std::__cxx11::basic_string<char>*&)'
I know that it must be really obvious but according to what I have searched for, it should work. Can someone point me in the right direction?
The problem is that when you pass an array to a function, it decays to a pointer to its first element.
It doesn't matter if you attempt to declare the argument as an array, the compiler still translates it as a pointer. string possible_names[] is equal to string* possible_names when you declare arguments.
The simple solution is to use either std::vector or std::array depending on your needs and use-case.
Using std::vector your code would look something like this:
std::vector<std::string> people_names = { "Mario", "Luigi" };
bool lookupTerm(const std::string& term, const std::vector<std::string>& possible_names) {
for (const std::string &possible_name : possible_names)
{
if (possible_name == term)
return true;
}
return false;
}
One line using std::find:
bool lookupTerm(const std::string& term, const std::vector<std::string>& possible_names) {
return std::find(possible_names.begin(), possible_names.end(), term) != possible_names.end();
}
If performance becomes a problem you can increase the performance of this by using a sorted vector (using std::sort) and std::lower_bound:
//at one point:
std::sort(people_names.begin(), people_names.end());
bool lookupTerm(const std::string& term, const std::vector<std::string>& sorted_possible_names) {
//sorted_possible_names must be always sorted when you call this!
auto i = std::lower_bound(sorted_possible_names.begin(), sorted_possible_names.end(), term);
return (i != sorted_possible_names.end() && *i == term);
}

c++ remove custom object from vector : std::remove_if': no matching overloaded function found

In my project there is a vector
std::vector<std::shared_ptr<MovingEntity>>gameObjects;
Which I want to delete elements from if they meet the criteria.
Method to delete elements:
void GameWorld::catchBees()
{
auto q = std::remove_if(bees.begin(), bees.end(), beeToClose);
bees.erase(q);
}
Method beeToClose:
bool GameWorld::beeToClose( const MovingEntity & bee)
{
std::shared_ptr<Beekeeper> keeper = std::static_pointer_cast<Beekeeper>(m_beekeeper);
if (bee.getConstPosition().distanceTo(m_beekeeper->getPosition()) > keeper->getCatchDistance())
{
return true;
}
return false;
}
When I try to compile the code I get some errors which I tried to understand:
'GameWorld::beeToClose': non-standard syntax; use '&' to create a
pointer
Not sure why this message is given
'std::remove_if': no matching overloaded function found
I did not declare beeToClose right?
'q': cannot be used before it is initialized SDLFramework
q is not initialized because:
std::remove_if(bees.begin(), bees.end(), beeToClose);
does not run correct?
How can I remove a std::shared_ptr correctly from a vector correctly when meeting some criteria?
The syntax for forming a pointer to member function is &ClassName::FunctionName. So you need &GameWorld::beeToClose for a pointer to the beeToClose member function. In your case, you should use a lambda from which you call that function
auto q = std::remove_if(bees.begin(), bees.end(),
[&](shared_ptr<MovingEntity> const& bee){ return beeToClose(bee); });
Also, you're using the wrong vector::erase overload, you want the one that erases a range of elements, not the one that erases a single element.
bees.erase(q, bees.end());
The vector contains std::shared_ptr<MovingEntity> elements, so beeToClose() needs to accept a const std::shared_ptr<MovingEntity> & parameter as input, not a const MovingEntity & parameter. Also, beeToClose() appears to be a non-static class method that accesses a non-static class member (m_beekeeper), so you can't just pass beeToClose() directly to std::remove_if() as it does not have access to the calling object's this pointer, but you can wrap it in a lambda to capture the this pointer.
Try this:
void GameWorld::catchBees()
{
auto q = std::remove_if(bees.begin(), bees.end(),
[this](const const std::shared_ptr<MovingEntity> &bee) {
return this->beeToClose(bee);
}
);
bees.erase(q, bees.end());
}
bool GameWorld::beeToClose(const std::shared_ptr<MovingEntity> &bee)
{
std::shared_ptr<Beekeeper> keeper = std::static_pointer_cast<Beekeeper>(m_beekeeper);
return (bee->getConstPosition().distanceTo(m_beekeeper->getPosition()) > keeper->getCatchDistance());
}
You might also consider moving the distance calculation into Beekeeper instead:
bool GameWorld::beeToClose(const std::shared_ptr<MovingEntity> &bee)
{
std::shared_ptr<Beekeeper> keeper = std::static_pointer_cast<Beekeeper>(m_beekeeper);
return !keeper->isInCatchDistance(bee);
}
bool Beekeeper::isInCatchDistance(const std::shared_ptr<MovingEntity> &bee)
{
return (bee->getConstPosition().distanceTo(getPosition()) <= getCatchDistance());
}

Cannot convert 'this' pointer from 'const Bullet' to 'Bullet &'

I am trying to use a list for my bullets.
Whenever I run my update bullet code it gives me this error:
Error 1 error C2662: 'Bullet::detectCollision' : cannot convert 'this' pointer from 'const Bullet' to 'Bullet &'
my list:
std::list<Bullet> bullet_list;
my update code:
std::list<Bullet>::const_iterator cIter;
for ( cIter = bullet_list.begin( ); cIter != bullet_list.end( ); cIter++ )
{
if((*cIter).detectCollision(monster.position,monster.getHeight(),monster.getWidth()))
{
//Do stuff here
}
if ((*cIter).detectCollision(boss.getPosition(),boss.getHeight(),boss.getWidth()))
{
//Do stuff here
}
}
my detect collision code:
bool Bullet::detectCollision(Vector objTwo,int heightT,int widthT)
{
if(position.getVectorX() >= objTwo.getVectorX() - (widthT/2) && position.getVectorX() <= objTwo.getVectorX() + (widthT/2)
&& position.getVectorY() >= objTwo.getVectorY() - (widthT/2)&& position.getVectorY() <= objTwo.getVectorY() + (heightT/2) && alive)
{
return false;
}
return true;
}
You need to declare detectCollision as const.
bool Bullet::detectCollision(Vector objTwo,int heightT,int widthT) const
When you don't, it's trying to do a conversion so it can call a non-const function on a const reference but it's not allowed.
You are using const_iterator but trying to access a non-const member function. Either use iterator instead of the const_iterator or declare the function as const if it can be a const member function.
A const_iter does not allow the values it points at to be changed, so when you're calling detectCollision you need to promise the compiler you also won't change those values(make the function const).

Error in custom struct set declaration

I'm getting a weird compiler error and as I'm new to using set's with custom struct's I'm not sure what exactly the problem is.
I'm trying to create a set of "pair's" and am using a custom comparison function for inserting said pair's.
struct pairT {
std::string first, second;
};
int PairCmp(pairT &one, pairT &two) {
if (one.first < two.first && one.second == two.second) return 0;
else if (one.first < two.first) return -1;
else if (one.first == two.first && one.second < two.second) return -1;
return 1;
}
std::set<pairT> CartesianProduct (std::set<std::string> &one, std::set<std::string> &two) {
std::set<pairT> returnSet(PairCmp);
/.../
I'm getting the error from the last line of code:
C2664 "can't convert parameter 1 from int to const std::less... blah, blah, blah.
Any suggestions as to why I'm getting my ass kicked?
Using objects (instead of pointers) requires that you name a second template parameter for std::set used to compare two objects of pairT. See std::less<> for an example.
Also, what you're trying here seems to be wrong. You're trying to return a std::set in CartesianProduct(), but the returned PairCmp() returns an integer.