2017-08-02 6 views
1

電話番号に基づいて連絡先の名前を検索できる連絡先の一覧を持つプログラムを作成しようとしています。そんなにコードを含むため申し訳ありませんが、それは私の問題を理解するために必要である:find()を使用したIteratorからstd :: setは機能しません。何がうまくいかないの?

#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; 
} 

私の問題は、常にラインauto findNumber = contactBook.find(userNumber);であると思われます。このコードを実行するたびに、「連絡先が見つかりません」というメッセージが表示されます。私は何が間違っているのか分かりません。それはoperator==の私の再定義ですか?

上記のコードはRao、Siddharthaからインスピレーションを受けています。 サムズは1時間に1時間でC++を教える第8版、インディアナ州インディアナポリス、サムス、2017年

答えて

1

std::set::findを使用しないでください。 std::set::findは完全一致を見つけることですが、部分一致を探しています。 std::set::findは、ソートされていることを知っているので、連絡先のサブセットのみを調べます。しかし、いずれかの電話番号が電話番号と一致する可能性があるため、すべての連絡先を確認する必要があります。

std::find_ifから<algorithm>までです。 std::find_ifは、これが正しいかどうかを判断できる関数または関数のようなオブジェクトである述語をとります。

まず、私たちは、述語のためのラムダを使用することができます<algorithm>

#include <algorithm> 

を含める:

auto findNumber = 
    std::find_if(contactBook.begin(), contactBook.end(), 
       [&userNumber](const ContactItem &contact) { 
       return contact.phoneNumber == userNumber; 
       }); 

あなたが前にラムダで働いていない場合、これはかなり奇妙に見えることができます。ラムダは、状態を持つ無名関数のようなものです。

角括弧[]は、これがラムダであることをコンパイラに伝えます。 &userNumberによれば、ラムダ本体には、現在のスコープにある変数userNumberへの参照が必要です。 (これは「参照によるキャプチャ」と呼ばれます。)

カッコは機能的なパラメータリストを囲みます。 std::find_ifは、連絡先への参照を渡すことによって、各連絡先でこのラムダを呼び出すことになります。

ラムダの本体(中括弧{})は、連絡先が渡されたかどうかを私たちの一致基準に合致させるためにboolを返す関数本体です。本文は、渡された引数だけでなく、定義されたスコープから「キャプチャされた」ものも参照できます。この場合、連絡先の電話番号が希望の電話番号と一致するかどうかだけが考慮されます。

0

デフォルトでstd::setdocumentationで述べたように、それは、この場合には、あなたがpovided ContactItem::operator<使用するstd::lessを使用しています。 nameフィールドで構造体を比較するとき、このフィールドは要素の比較に使用されるので、基本的に空の名前で連絡先を検索しようとしています。これには、std::setに異なるコンパレータを指定するか、それに応じてContactItem::operator <を変更する必要があります。

注:あなたもdocumentatioonで見ることができるようstd::unordered_setstd::setとは異なり、任意の形態でoperator==を使用していません:

のstd ::設定は、タイプの ユニークなオブジェクトのソートセットが含まれて連想コンテナでありますキー。並べ替えは、キー比較 関数比較を使用して行われます。

std::lessdocumentationは言う:比較を実行するための

Functionオブジェクト。専門ない限り、 は、ここでの問題はstd::setの要素を見つけるためにあなたのoperator ==を使用していないということです

+1

'演算子'は[厳密な弱い順序](https://www.sgi.com/tech/stl/StrictWeakOrdering.html)を実装しなければならないという価値があるかもしれません。初心者はしばしば間違っています。 –

+0

この回答はすべて当てはまりますが、実際に問題は解決されません。コンパレータを変更しても部分的に一致するアイテムは見つかりません。 –

+0

@AdrianMcCarthy名前を無視する比較器を使用し、この 'std :: set'のために電話を比較するだけで問題を解決できます。 – Slava

0

タイプTにオペレータ<を呼び出します。代わりに、それはoperator <であるオブジェクトを比較するために使用するものと同じものを使用します。あなたはを変更してphoneNumberと比較するか、名前付きの連絡先を指定する必要があります。

また、ブーストmulti-index containerと考えて、自分の名前と番号のインデックスを作成することもできます。

+0

マルチインデックスコンテナは解決策ですが、単純にコンパレータを変更すると、おそらく望ましくない別の影響があります(たとえば、2人の連絡先が電話番号を共有できない)。 –

関連する問題