I'm trying to iterate through a vector of Player objects and then return the next one based off a Player pointer. I have tried various ways to get the operators within the lambda to match but cannot get it to work and have read similar such issues on stack overflow. I'm sorry for not making a SSCCE, I just don't know how at my current skill level.
Source of c_player:
Defined as:
Player* current_player;
Set with:
void Game::set_first_player_turn(){
current_player = &game_players.back();
}
Erroneous code:
using namespace std;
vector<Player>game_players;
Player* Game::find_player(Player* c_player){
vector<Player>::iterator iter;
iter = find_if(game_players.begin(), game_players.end(),
[&](Player* p ) -> bool{ return p == c_player; }); //This line
// causes the exception. Sets iterator to
// position of the current player
if (iter != game_players.end()){
advance(iter, 1);
}
else{
iter == game_players.begin();
}
current_player = &(*iter);
return current_player;
}
Compile error:
error C2664: 'bool Game::set_game_flow::<lambda_360ac8a355100cfac1adc9f8eba8d8b9>
::operator ()(Player *) const' : cannot convert parameter 1 from 'Player'
to 'Player *'
Thanks for any help.
Predicate in find_if has to take a const reference to a type stored in container. You store a Player type in vector
vector<Player> game_players;
Thus
[&](Player* p )
is not a correct predicate. This should be
[c_player]( const Player& p ) { return p == *c_player; }
// ^^^^^^^^^^^^^^
// to compare by value
// note: to compare by value
// bool operator==( const Player&, const Player&)
// must be defined
[c_player]( const Player& p ) { return &p == c_player; }
// ^^^^^^^^^^^^^^
// to compare by address
// note: address of c_player
// has to be valid (not invalidated by vector through resizing, erasing, etc)
So you can write:
vector<Player>::iterator iter;
iter = find_if( game_players.begin(), game_players.end(),
[c_player]( const Player& p ) { return p == *c_player;});
Related
I am working on a file that I have to iterate through the object's vector but for some reason I am getting this error:
No viable conversion from '__wrap_iter<std::__1::vector<MenuItem *>::const_pointer>' to '__wrap_iter<std::__1::vector<MenuItem>::pointer>'
this is the line which causes the error:
for (vector<MenuItem>::iterator p = m->menuItems()->begin() ; p != m->menuItems()->end(); p++) {
the class function which I am trying to iterate through:
virtual const vector<MenuItem*>* menuItems() const = 0;
** the virtual function at the derived classes are:
virtual const vector<MenuItem*>* menuItems() const { return nullptr; }
virtual const vector<MenuItem*>* menuItems() const { return &m_menuItems; }
Edit:
After finding what I wanted to find with the iterator, I want to recall this function (recursive call) with the newfound item. however, when I am trying to do so, I am not matching the function call.
the function call is :
void listAll(const MenuItem* m)
the way I
for (vector<MenuItem*>::const_iterator p = m->menuItems()->begin() ; p != m->menuItems()->end(); p++) {
cout << (*p)->name();
if ((*p)->menuItems() == nullptr) {
cout << endl;
}
if ((*p)->menuItems() != nullptr) {
cout << endl;
vector<MenuItem*>::const_iterator k = (*p)->menuItems()->begin();
MenuItem* mPtr = *k;
listAll(mPtr);
There are two problems here. First, a function with the signature
const vector<MenuItem*>* menuItems() const;
(virtual or not) returns a pointer to a const-qualified instance of a vector. The begin() and end() member functions of const-qualfied vectors return const_iterators, not iterators. As it makes sense that you can't convert a const_iterator into an iterator, this is an issue.
Second, you are missing an asterisk in the type of the iterator. So the correct type specifier should be
vector<MenuItem*>::const_iterator p = m->menuItems()->begin(); ...
// ^ ^^^^^^
Using auto type deduction for iterator types is a common pattern, so you could also do
for (auto p = m->menuItems()->begin() ; p != m->menuItems()->end(); p++)
{ /* ... */ }
there is class like as
class C_Service
{
public :
C_Service(); {memset(this, 0, sizeof(*this));}
C_Service(int type, int idx) {memset(this, 0, sizeof(*this)); this->type = type; this->idx = idx;}
bool operator==(const C_Service& svc) const { return (this->type == svc.type && this->idx == svc.idx);}
word type;
word idx;
dword aId;
dword bId;
char* name;
};
I used test code as below,
void vec_find(int type, int idx)
{
vector<C_Service*> vec;
// added several items in vector vec
...
vector<C_Service*>::iterator iter;
C_Service cSvc(type, idx);
iter = find(vec.begin(), vec.end(), &cSvc);
C_Service* findsvc = *iter;
if(findsvc)
printf("FOUND : type(%d), idx(%d), name(%s)\n", findsvc->type, findsvc->idx, findsvc->name);
else
printf("Not FOUND!!\n");
}
then, it give "Not FOUND!!" even set correct value.
I found something wrong and trying change..
iter = find(vec.begin(), vec.end(), &cSvc);
to
iter = find(vec.begin(), vec.end(), cSvc);
remove "&"
then it give compile error message
/libcxx/algorithm: In instantiation of '_InputIterator
std::__1::find(_InputIterator, _InputIterator, const _Tp&) [with
_InputIterator = std::__1::__wrap_iter; _Tp = C_Service]':
no match for 'operator==' (operand types are 'C_Service*' and 'const
C_Service')
I searched that when I use find() function in Container, It can use operator==
but, I can't get a goal..T.T
What is my fault?
The problem is that your vec is a vector of pointers, not a vector of C_Service objects.
Thus
find(vec.begin(), vec.end(), &cSvc)
checks whether the address of the cSvc variable is contained within vec (which it's not because you just created cSvc so it can't be referenced from anywhere else). It does not use your operator== at all, it just compares pointers.
To fix it, you can either change vec to be a std::vector<C_Service> and do
find(vec.begin(), vec.end(), cSvc)
or pass a custom predicate to find_if, where you can dereference your pointers manually:
find_if(vec.begin(), vec.end(), [&](const C_Service *p) { return *p == cSvc; })
I have a container of container of ints. Lets say deque< deque<int> >. All the numbers in the deque<int> are sorted in ascending order. So the info in the container looks something like this:
deque<deque<int>> // main container
5 11 22 44 // deque<int> number 1
1 7 12 // deque<int> number 2
4 5 7 9 1112 // deque<int> number 3
I want to make an iterator that traverses thru all the numbers in deque<deque<int>> in ascending order. Meaning my iterator can jump between the containers and after I've gone through them all I will have traversed thru the numbers in this order: 1 4 5 5 7 7 9 11 12 22 44 1112. How can I accomplish this? I thought of putting all the numbers in one container and sorting them, but later if I want to say *it = 10 I won't be able because I don't know to which containers position is it pointing. So any ideas and solutions are welcomed :)
Let's focus on a const iterator. Such an iterator should hold an iterator to each of the deques, but also to each of their end (why you need this is explained below). But these iterators should be held in a vector instead of a deque, because you will never push or pop from either end of these containers, since the lifetime of such an iterator ends with a modification of your data structure.
So basically, you need the following structure:
struct const_iterator {
vector<deque<int>::const_iterator> iterators;
vector<deque<int>::const_iterator> ends;
//...
};
Now, you need to implement the increment operator (maybe you also want a decrement operator, which can be implemented analogously), as well as the dereferencing operator.
The increment operator needs to find the deque iterator which currently points to the smallest element, and increment that one.
The dereferencing operator also needs to find the deque iterator which currently points to the smallest element, and dereference that one.
If you're looking for the currently smallest element, ignore the deques which already point to their end. For this, you need all the deque's end iterators. It might be helpful to remember the currently smallest element in another member variable, such that dereferencing becomes a constant time operation. We store that current iterator as an iterator into the vector of iterators, such that we can increment it (so the iterator in the vector is changed).
struct nested_deque_iterator {
vector<deque<int>::const_iterator> iterators;
vector<deque<int>::const_iterator> ends;
vector<deque<int>::const_iterator>::iterator current;
bool at_end = false;
};
Updating the smallest element could be implemented in a helper function, which modifies the member variable current as well as at_end. This needs to be called in the constructor for a correct initialization of the member variable:
void update_current() {
if (!at_end && iterators.size() > 0) {
// At the beginning, we assume that we didn't find any
// new "next smaller element" in any deque.
at_end = true;
// Iterate through the deques (with two iterators in parallel)
for (auto i = iterators.begin(), e = ends.begin();
i != iterators.end() && e != ends.end();
++i, ++e)
{
// We ignore deques which are already at their end
if (i != e) {
// If we found a smaller next element (or the first try)...
if (at_end || *i < *next) {
// ... then replace the current iterator with it:
at_end = false;
current = i;
}
}
}
}
}
Then, dereferencing becomes as easy as dereferencing the current iterator twice (since it is an iterator into the vector of iterators... I know it is a bit confusing...)
int operator *() const {
return **current;
}
And incrementing will increment the (dereferenced) current iterator, as well as call the helper function to update it (this is the pre-increment operator):
nested_deque_iterator& operator++() {
if (!at_end) {
++(*current);
update_current();
}
}
You can implement the post-increment operator by means of pre-incrementing:
nested_deque_iterator operator++(int) {
nested_deque_iterator old(*this);
++(*this);
return old;
}
We also need the equality operator to compare iterators with each other:
bool operator==(const nested_deque_iterator &o) const {
// If either iterator is at the end, don't dereference current!
if (at_end || o.at_end) {
return at_end == o.at_end;
}
return *current == *(o.current);
}
And finally the inequality operator by means of equality:
bool operator!=(const nested_deque_iterator &o) const {
return !(*this == o);
}
Finally, write a begin and end construction helper function for your nested deques.
nested_deque_iterator nested_deque_begin(const deque<deque<int>> & deques) {
vector<deque<int>::const_iterator> iterators;
vector<deque<int>::const_iterator> ends;
for (const auto & d : deques) {
iterators.push_back(d.begin());
ends.push_back(d.end());
}
return { iterators, ends };
}
nested_deque_iterator nested_deque_end(const deque<deque<int>> & deques) {
vector<deque<int>::const_iterator> ends;
for (const auto & d : deques) {
ends.push_back(d.end());
}
return { ends, ends };
}
And if you want to, also a container adaptor (if you don't already have such) which uses these construction helper functions as their default begin and end methods:
struct nested_deque {
deque<deque<int>> deques;
//...
}
nested_deque_iterator begin(const nested_deque & nd) {
return nested_deque_begin(nd.deques);
}
nested_deque_iterator end(const nested_deque & nd) {
return nested_deque_end(nd.deques);
}
So you can write:
deque<deque<int>> mydeque = ...;
for (int i : nested_deque{mydeque}) {
// Here you go.
}
The full implementation is available here.
Implement your own iterator:
struct sorted_iterator {
int& operator*() { return *(*this->it); }
sorted_iterator& operator++() { ++(this->it); return *this;}
bool operator==( const sorted_iterator& other ) const;
bool operator!=( const sorted_iterator& other ) const;
private:
std::vector<int*> sorted;
decltype(sorted)::iterator it;
};
and in it, internally, build a vector of int*
std::vector<int*> sorted;
for( std::deque<int> x : main_container )
for( int& i : x )
sorted.push_back(&i);
auto compare = []( int* i, int* j ) { return *i < *j; }
std::sort( sorted.begin(), sorted.end(), compare );
I have a function which return value if a key exist in map like:
map<int,string> mymap;
//Assume there are some key value pair in above map
string & ReturnKey(int &a)
{
string ret;
map<int,string>::iterator iter = mymap.find(a);
if(iter not_eq mymap.end())
{
ret = iter->second;//I think this will make copy
}
else
return ret;
}
How can I avoid copy of string which is returning from above function?
If you're okay with the returned reference being const, you can do something like this:
const string & ReturnKey(int a)
{
static const string defaultValue; // to be returned if object isn't found
map<int,string>::iterator iter = mymap.find(a);
if(iter != mymap.end())
{
return iter->second;
}
else return defaultValue;
}
It's safe to return a reference to (defaultValue) in the not-found case because defaultValue is declared static and therefore will still exist after the function returns. In the value-found case, the caller will need to be careful not to hold the reference and try to use it after mymap has been cleared or modified, but that's usually not an issue in practice.
You can return a reference to an existing string or raise an exception if it doesn't exist. This is easily done with the std::map::at method:
string& ReturnKey(int a)
{
return mymap.at(a);
}
If you are stuck with a pre-C++11 compiler, you have to do it by hand:
string& ReturnKey(int a)
{
map<int,string>::iterator iter = mymap.find(a);
if(iter == mymap.end())
throw std::out_of_range("Invalid key");
return iter->second;
}
As in your program you can not return the reference of the variable declared inside the function because as the function complete the execution all the variable declared inside that function will get released and deleted.
So in that case you will get null or garbage value every time the function will called.
For this In my opinion you can pass your string argument as a reference in the function.
so, by using this you can get your desired value in your variable.
Or
You can also change the return type of the function to std::string.
I think You have to use this function as:
map<int,string> mymap;
//Assume there are some key value pair in above map
void ReturnKey(int &a, string& str)
{
map<int,string>::iterator iter = mymap.find(a);
if(iter not_eq mymap.end())
{
str = itr->second;
}
}
Or you can return std::string values for status of your operation.
As follows:
map<int,string> mymap;
//Assume there are some key value pair in above map
std::string ReturnKey(int &a)
{
std::string ret;
map<int,string>::iterator iter = mymap.find(a);
if(iter not_eq mymap.end())
{
ret = iter->second;//I think this will make copy
}
else{
delete ret;
return null;
}
return ret;
}
and #include <string> should be used.
Hope this will help you.
I am trying to return a Vertex &, here's the code:
Vertex& Graph::getVertex(std::string v) { // gets the vertex
for (std::vector<Vertex>::iterator it = vertices.begin(); it != vertices.end(); it++) {
if ((it->getName()).compare(v) == 0)
return it; // if strings are the same return vertex
}
exit(1);
}
The problem is that getVertex is flagged as incompatible and it in the return is flagged as a reference of type Vertex & (non-const qualified) cannot be initialized with a value with of type std::vector ...
How would I fix these errors?
You're trying to return the iterator, not what the iterator points to. So you need to return *it.