Reputation: 41
I am trying to create a program that has a list of contacts where the user can search for a contact's name based on a phone number. Sorry for including so much code but it is necessary for understanding my problem:
#include <iostream>
#include <string>
#include <set>
using namespace std;
struct ContactItem
{
string name;
string phoneNumber;
string displayAs;
ContactItem(const string inName, const string inNumber) : name(inName), phoneNumber(inNumber)
{
displayAs = name + ": " + phoneNumber;
}
bool operator== (const ContactItem& searchParameter) const
{
return (this->phoneNumber == searchParameter.phoneNumber);
}
bool operator< (const ContactItem& compareResult) const
{
return (this->name < compareResult.name);
}
operator const char*() const
{
return displayAs.c_str();
}
};
int main()
{
//Initialize a set and populate it with contacts of type ContactItem
set<ContactItem> contactBook;
contactBook.insert(ContactItem("Sally", "123654864"));
contactBook.insert(ContactItem("Joe", "8435102654"));
contactBook.insert(ContactItem("Steve", "8135691234"));
contactBook.insert(ContactItem("Alice", "8432489425"));
//Search for a contact's name by only being given their number
cout << "Please give the number of one contact whose name you would like to know: " << endl;
string userNumber;
getline(cin, userNumber);
auto findNumber = contactBook.find(ContactItem("", userNumber));
if (findNumber != contactBook.end())
cout << "The name of the contact whose number matches the phone number given is: " << (*findNumber).name << endl;
else
cout << "Contact not found" << endl;
return 0;
}
My problem always seems to be with the line auto findNumber = contactBook.find(userNumber);
. Every single time I run this code, the message "Contact not found" is displayed. I can't figure out what I'm doing wrong. Is it my redefinition of operator==
?
The above code was inspired by Rao, Siddhartha. Sams Teach Yourself C++ in One Hour a Day. 8th ed., Indianapolis, IN, Sams, 2017.
Upvotes: 1
Views: 827
Reputation: 48038
You don't want to use std::set::find
to do this. std::set::find
is to find an exact match, but you're looking for a partial match. std::set::find
is going to look at only a subset of the contacts because it knows they are sorted. But you need to check all of the contacts, because any one of them could match the phone number.
What you need is std::find_if
from <algorithm>
. std::find_if
takes a predicate, which is a function or function-like object that can tell if you if this is the right one.
First, include <algorithm>
#include <algorithm>
We can use a lambda for the predicate:
auto findNumber =
std::find_if(contactBook.begin(), contactBook.end(),
[&userNumber](const ContactItem &contact) {
return contact.phoneNumber == userNumber;
});
If you haven't worked with lambdas before, this can look pretty weird. A lambda is like a nameless function with state.
The square brackets []
tell the compiler that this is a lambda. The &userNumber
says that, in the body of the lambda, we're going to need a reference to the userNumber
variable that's in the current scope. (This is called "capture by reference.")
The parentheses enclose a function-like parameter list. std::find_if
is going to invoke this lambda on each contact, as though it were a regular function, by passing in a reference to the contact.
The body of the lambda (in braces {}
) is a function body that returns a bool
to tell use whether the contact passed in meets our criteria for a match. The body can reference the arguments passed in as well as anything "captured" from the defining scope. In this case, we just care whether the contact's phone number matches the desired phone number.
Upvotes: 2
Reputation: 181068
The issue here is that std::set
does not use your operator ==
to find the element. Instead it uses the same thing it uses to compare objects which is the operator <
. You're either going to have to change your operator <
to compare by phoneNumber
or provide a named contact.
You could also consider a boost multi-index container that would allow you to index my name and number.
Upvotes: 0
Reputation: 44288
As stated in std::set
documentation by default it uses std::less
which in this case uses ContactItem::operator<
you povided. As you compare structs by name
field - this field is used in comparing elements, so basically you are trying to find contact with empty name. You either need to specify different comparator for this std::set
or change ContactItem::operator <
accordingly.
Note: unlike std::unordered_set
std::set
does not use operator==
in any form, as you can also see in documentatioon:
std::set is an associative container that contains a sorted set of unique objects of type Key. Sorting is done using the key comparison function Compare.
and std::less
documentation says:
Function object for performing comparisons. Unless specialized, invokes operator< on type T.
Upvotes: 0