So I have a custom object called WaterJug and I'm getting errors when calling functions on a global set<WaterJug>:
This is defined before the class definition:
set<WaterJug> memo;
And in one of the methods of my class:
for(std::vector<WaterJug>::iterator newJug = newJugs.begin(); newJug != newJugs.end(); ++newJug) {
const bool is_in = memo.find(newJug); //error here
if (is_in) {
}
}
Error is: No matching member function for call to 'find'
Do I have to implement any interfaces in my custom class for the set operations to work?
You have couple of errors.
Wrong argument being passed to memo.find.
memo.find(newJug) // tpe of newJug is an iterator, not an object.
It needs to be
memo.find(*newJug)
The return value of memo.find() is not a bool. It is an iterator. Instead of
const bool is_in = memo.find(newJug); //error here
if (is_in) {
use:
if ( memo.find(*newJug) != memo.end() )
std::set::find takes an object, newJug is an an iterator, not an object, to access the object "pointed" by the iterator, you need to dereference newJug: *newJug:
Moreover, find returns an iterator, not a bool, it returns end() iterator of object os not found.
This version of the code will work:
for(std::vector<WaterJug>::iterator newJug = newJugs.begin(); newJug != newJugs.end(); ++newJug) {
const bool is_in = ( memo.find(*newJug) != memo.end() );
if ( is_in ) {
}
}
std::set::find only takes parameter of the key type of the set. When you use memo.find(newJug) you are calling find with an iterator to a key and not a key. You can dereference the iterator to get a key value memo.find(*newJug);.
You also have an issue with the fact that you are trying to store the return from find as a bool when find returns an iterator. If you want to know if find found something then you can rewrite
const bool is_in = memo.find(newJug);
To
const bool is_in = (memo.find(newJug) != memo.end());
Related
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());
}
I am writing a template function which takes in a vector and a struct, and inserts that struct into the vector. If there is a duplicate struct in the vector however,the function will not insert the struct because the values must all be unique. In order to do this, I am using the find function of the STL library, and analyzing the return value using the operator==. However, I am getting this error every time I try and compile:
error: no match for 'operator==' (operand types are 'OneToOneMap' and'OneToOneMap')|
My template function can be seen below:
template<typename Type> void AddToList(vector<Type> add_to, Type to_insert){
bool contains_element = *find( add_to.begin(), add_to.end(), to_insert) == *add_to.end() ? false:true;
if(contains_element){
cout << "Element is already in list" << endl;
}else{
add_to.push_back(to_insert);
}
}
The question isn't entirely clear however I suspect you haven't overloaded the operator== in the class/struct OneToOneMap which you are trying to compare in your code. Assuming this is a user-defined type, overload this operator (and operator!=) as follows:
class OneToOneMap {
public:
//...
bool operator==(const OneToOneMap& _other) const {
// do comparison based on fields
}
bool operator!=(const OneToOneMap& _other) const {
return !(*this == _other);
}
};
Edit
Ineed, you need to provide an overload for the type that you want to use std::find<T>() on! The reason is that of course the function needs a way to compare the container elements to find out if they're equal or not. Provide an overload for the bool T::operator==(const T& other) as ArchbishopOfBanterbury has noticed.
(To be more exact, comparison using the bool operator==(...) is used when the user has not provided another predicate to compare the elements, see http://en.cppreference.com/w/cpp/algorithm/find)
Original answer:
Remove the unnecessary dereference operators * when comparing iterators:
bool contains_element = find( add_to.begin(), add_to.end(), to_insert) == add_to.end() ? false:true;
You don't need the false : true either, since the comparison returns a bool:
bool contains_element = find( add_to.begin(), add_to.end(), to_insert) == add_to.end();
The logic is that the std::find<T>() function returns an iterator, and you compare that iterator to the vector<T>::end() iterator, i.e. the "null" iterator, to check if find<T>() has been able to find anything or not. You don't need to compare the T values themselves.
I have a function below that searches through a vector of my_type. Currently, it has a compilation warning: control reaches end of non-void function [-Wreturn-type]. It appears that as long as I am using a reference as my return type rather than a pointer, it is not possible to return a null-like value?
struct my_type{
type_a a;
type_b b;
}
type_b& value(type_a& t){
typename std::vector<my_type>::iterator it;
for(it = v.begin(); it != v.end(); ++it){
if ((*it).a == t) return (*it).b;
}
}
It appears that as long as I am using a reference as my return type rather than a pointer, it is not possible to return a null-like value?
Well, yes, but that's not the only issue. References can never be null, but what happens if your if statement never evaluates to true? You don't return anything.
Since references cannot be null, it is not valid to return null. You must return a valid reference from all execution paths.
Also, your code is fragile at best. You are returning a reference to a member of an element in a container... an element that may be moved at any point in the future, making said reference invalid.
The question you have to think about is what should you return if 'nothing' is found when your function has to return my_type. How you handle this directly affects how the caller uses this function and assumptions made.
There are a few ideas you can think about. For example, if your value function returned a pointer type, you could just return NULL to indicate nothing. If it returned a string, you can use an empty string "" or even a special string value like "none" to indicate that. For type_b you can create a special instance of it and just return that instance to indicate nothing. Other functions calling this would check the returned type_b against that instance to see if it's nothing. The point is, there are many ways to go about it and which way you choose is up to you.
But a better approach would be to use what's already provided by the stl -- in particular std::find_if. For example, you can create a functor which specifies when there's a match:
struct find_b
{
const type_a &this_a;
find_b(const type_a &a) : this_a(a) {}
bool operator() (const my_type &lhs)
{
return lhs.a == this_a;
}
};
Then you would use it like this:
item = std::find_if(v.begin(), v.end(), find_b(t));
if(item == v.end()) { /* not found */ }
else { /* found, do something useful here */ }
I am working on a simple hash table in C++. I have methods to insert, delete, and search the hash table for the specified key. I know that the C++ map STL container can handle my situation, but I would kind of like to code my own as an educational exercise.
Basically I have a hash table that will take a single string and map it to a vector of other strings. This is easy to do in a method because calling a .Add() or .Delete() will behave as expected. I would however like to create an overloaded [] operator to the class that is able to do these operations on the vector.
For example, if I want to add an item to the vector I can write something like this:
hashTable[string1] = newString;
This will set the new string as a member of my vector. The same can be said for delete and search.
hashTable[string1] = "";
cout << hashTable[string1] << endl;
My major problem is that I do not know how to overload the [] operator to gain this functionality. I have this function coded up right now. It works on a basic 1 to 1 string match, but not on a string to vector match.
//Return a reference to a vector to update then reassign?
vector& HashClass::operator[](const string index)
{
assert(size >= 0 && size < maxSize);
Hash(key);
return hashTable[index];
}
I think I'm most stuck on the idea of having a vector return that later needs to be assigned. As the user, I would find this kludgy.
This question is closely related to another question: what behavior do
you want when you access a non-existant value other than in an
assignment? In other words, what do you want to happen when you write:
std::cout << hashTable[string] << std::endl;
and string is not present in the table?
There are two possible approaches: you can consider it an error, and
throw an exception, or abort, or something similar; or you can return
some sort of default, built with the default constructor, or provided by
the client earlier.
The standard map and unordered_map take the second approach, using the
default constructor to construct a new value. This allows a very simple
solution: if operator[] isn't present, you insert it, initializing it
with the default value. Then you return a reference to it;
hashTable[string] = newString; assigns through the reference to an
already existing value.
In many use cases, the first approach will be preferable (perhaps with a
contains function, so you can test up front whether the operator[]
will find something or not). To implement the first approach, you must
first implement specific functions for each type of access:
template <typename Key, typename Value>
class HashTable
{
public:
Value* get( Key const& key ) const;
void set( Key const& key, Value const& value );
};
(I generally make these public; there's no reason to forbid their use by
a client.)
Then, you define operator[] to return a proxy, as follows:
template <typename Key, typename Value>
class HashTable
{
public:
class Proxy
{
HashTable* myOwner;
Key myKey;
public:
Proxy( HashTable* owner, Key const& key )
: myOwner( owner )
, myKey( key )
{
}
operator Value const&() const
{
Value const* result = myOwner->get( myKey );
if ( result == NULL ) {
// Desired error behavior here...
}
return *result;
}
Proxy const& operator==( Value const& value ) const
{
myOwner->set( myKey, value );
return *this;
}
};
Value* get( Key const& key ) const;
void set( Key const& key, Value const& value );
Proxy operator[]( Key const& key )
{
return Proxy( this, key );
}
};
Thus, when you write:
hashTable[key] = newString;
, the proxy's operator= will call hashTable.put( key, newString );
in other contexts, however, it will call the implicit type conversion on
the proxy, which calls hashTable.get( key ).
In some cases, even if you desire to return a default value, it may be
preferable to use this solution: the get function is not required to
insert anything into the hash table, so the table doesn't fill up with
all of the misses, and you can overload the operator[] on const, so
you can use it on a const hash table as well. Also, it doesn't
require the value type to have a default constructor.
It does have one disadvantage with respect to the solution used in the
standard; since you can't overload operator., you can't make the proxy
behave like a reference, and things like:
hashTable[string].someFunction();
don't work. A work-around is to overload operator-> in the proxy, but
this leads to a somewhat unnatural syntax:
hashTable[string]->someFunction(); // But the hash table contains
// values, not pointers!!!
(Don't be mislead by the implicit conversion to a reference. An
implicit conversion will not be considered for a in an expression
a.b.)
In C++, [] access to associative containers is generally given the semantics of default-constructing an object of the mapped type, inserting it with the key, and returning a reference to the inserted mapped object.
So your operator[] would be implemented as:
string& HashClass::operator[](const string index)
{
assert(size >= 0 && size < maxSize);
Hash(key);
vector &v = hashTable[index];
if (index in v) {
...
} else {
v.push_back(string());
return v.back();
}
}
If I want the unordered map find function to return a bool value, how would I go about doing that?
Here's my code right now.
bool NS_SymbolTable::SymbolTable::Contains(std::string lexeme)
{
SymbolTable *tempSymbolTable = this;
std::unordered_map<std::string, Identifier*>::iterator it = tempSymbolTable->hashtable.find(lexeme);
return std::boolalpha;
}
What else do I neeed to do ? Is it possible to return a bool? There is little to no documentation on this that I have found.
This is where I got an example from http://msdn.microsoft.com/en-us/library/bb982431.aspx
tempSymbolTable->hashtable.find(lexeme) will return tempSymbolTable->hashtable.end() if it fails, so you can convert this result to a bool very simply:
return tempSymbolTable->hashtable.find(lexeme) != tempSymbolTable->hashtable.end();
Also, assigning this to a temporary variable and working through that is unnecessary. Your function can be reduced to:
bool NS_SymbolTable::SymbolTable::Contains(std::string lexeme)
{
return hashtable.find(lexeme) != hashtable.end();
}
For documentation look std::unordered_map::find. There it says:
Return value
iterator to an elements with key key. If no such element is found, past-the-end (see end()) iterator is returned.
To get boolean value indicating whether an element is present, use
bool contained = it != tempSymbolTable->hashtable.end();
bool NS_SymbolTable::SymbolTable::Contains(std::string lexeme)
{
SymbolTable *tempSymbolTable = this;
return tempSymbolTable->hashtable.end() != tempSymbolTable->hashtable.find(lexeme);
}
You need to test the return value of find against tempSymbolTable->hastable.end(), if they are equal then it did not find your element. The reason find works like this is because in its current form it is more general than something that returns only a bool.
std::unordered_map::find(), like the rest of the standard containers' find functions, returns end() on failure.
Try this:
bool NS_SymbolTable::SymbolTable::Contains(std::string lexeme)
{
SymbolTable *tempSymbolTable = this;
std::unordered_map<std::string, Identifier*>::iterator it =
tempSymbolTable->hashtable.find(lexeme);
return it != tempSymbolTable->hashtable.end();
}
Reference:
MSDN unordered_map::find
MSDN unordered_map::equal_range
EDIT: change sense of return value.