2016-09-26 68 views
0

我試圖使用地圖來存儲使用座標x,y作爲關鍵字的地圖信息。我無法使用自動迭代器或map.find()正確迭代這個映射。它只是不會給我返回正確的地圖值。我使用C++ 14,這裏是我的代碼塊:無法在C++映射中使用struct作爲鍵找到插入的值

#include <iostream> 
#include <string> 
#include <map> 
#include <iterator> 
#include <vector> 

using namespace std; 

struct mapPoint { 
    int X; 
    int Y; 

    bool operator < (const mapPoint &coord) const { 
    if (X == coord.X && Y == coord.Y) { 
     return true; 
    } else { 
     return false; 
    } 
    } 
}; 

struct explorerNotes { 
    bool foundCoin; 
    int timesVisitedThisBlock; 
    vector<bool> unexploredEntrances; // 0 0 0 0 -> N S E W 
    explorerNotes():timesVisitedThisBlock(0),unexploredEntrances(4,false){} 
}; 

int main() { 
    map<mapPoint, explorerNotes> explorerNotebook; 

    explorerNotes testNote1, testNote2, testNote3; 
    mapPoint testCoord1, testCoord2, testCoord3; 

    testNote1.foundCoin = true; 
    testNote1.timesVisitedThisBlock = 42; 
    testNote1.unexploredEntrances = {true, true, false, false}; 
    testCoord1.X = 25; 
    testCoord1.Y = 3; 

    testNote2.foundCoin = false; 
    testNote2.timesVisitedThisBlock = 314; 
    testNote2.unexploredEntrances = {false, true, false, false}; 
    testCoord2.X = 11; 
    testCoord2.Y = 2; 

    testNote3.foundCoin = true; 
    testNote3.timesVisitedThisBlock = 420; 
    testNote3.unexploredEntrances = {false, true, false, false}; 
    testCoord3.X = 1; 
    testCoord3.Y = 1; 

    explorerNotebook.insert(pair<mapPoint, explorerNotes>(testCoord1, testNote1)); 
    explorerNotebook.insert(pair<mapPoint, explorerNotes>(testCoord2, testNote2)); 
    explorerNotebook.insert(pair<mapPoint, explorerNotes>(testCoord3, testNote3)); 

    map<mapPoint, explorerNotes>::iterator p; 
    p = explorerNotebook.find(testCoord1); 
    cout << " testing 1:" 
     << "\nfoundCoin: " << p->second.foundCoin 
     << "\ntimesVisitedThisBlock: " << p->second.timesVisitedThisBlock 
     << "\nunexploredEntrances: "<< "(" << p->second.unexploredEntrances[0] << "," << p->second.unexploredEntrances[1] << "," << p->second.unexploredEntrances[2] << "," <<p->second.unexploredEntrances[3] << ")" << endl; 

    map<mapPoint, explorerNotes>::iterator q; 
    q = explorerNotebook.find(testCoord2); 
    cout << " testing 2:" 
     << "\nfoundCoin: " << q->second.foundCoin 
     << "\ntimesVisitedThisBlock: " << q->second.timesVisitedThisBlock 
     << "\nunexploredEntrances: "<< "(" << q->second.unexploredEntrances[0] << "," << q->second.unexploredEntrances[1] << "," << q->second.unexploredEntrances[2] << "," <<q->second.unexploredEntrances[3] << ")" << endl; 

    map<mapPoint, explorerNotes>::iterator r; 
    r = explorerNotebook.find(testCoord3); 
    cout << " testing 3:" 
     << "\nfoundCoin: " << r->second.foundCoin 
     << "\ntimesVisitedThisBlock: " << r->second.timesVisitedThisBlock 
     << "\nunexploredEntrances: "<< "(" << r->second.unexploredEntrances[0] << "," << r->second.unexploredEntrances[1] << "," << r->second.unexploredEntrances[2] << "," <<r->second.unexploredEntrances[3] << ")" << endl;; 

    return 0; 
} 

當我編譯此代碼它給我的輸出:

testing 1: 
foundCoin: 1 
timesVisitedThisBlock: 42 
unexploredEntrances: (1,1,0,0) 
testing 2: 
foundCoin: 1 
timesVisitedThisBlock: 42 
unexploredEntrances: (1,1,0,0) 
testing 3: 
foundCoin: 1 
timesVisitedThisBlock: 42 
unexploredEntrances: (1,1,0,0) 

它只是重複第一附加值..我整天呆着。有任何想法嗎?提前致謝。

+3

你的'operator <'是錯誤的。它必須實現[嚴格的弱排序](https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings) –

+3

你可以通過使用'std :: pair'或者'std :: tuple'來避免這個問題,它實現'操作者<'。 –

回答

4

你的operator <是完全搞砸了。

如果A的X座標相等且Y座標相等,則表示A小於B.所以(1,1)<(2,2)是錯誤的,但是(1,1)<(1,1)爲真。難怪地圖無法找到正確的條目。

特別是:

  • 由於(1,1)<(2,2)是假,和(1,1)>(2,2)是假的(>被<與參數反轉),這意味着(1,1)和(2,2)必須相等!因爲(1,1)<(1,1)爲真,所以(1,1)>(1,1)不可能是真的,因爲一件事不能小於另一件事,並且大於另一件事。然而它是。

您需要計算點的實際訂單,並在operator <中執行該訂單。例如,你可以說(a,b)<(c,d)如果是< c,或者a == c和b < d。那麼你得到的是(1,1)<(1,2)<(1,3)<(2,0)<(2,1)< ...

bool operator < (const mapPoint &coord) const { 
    if (X < coord.X || (X == coord.X && Y < coord.Y)) { 
     return true; 
    } else { 
     return false; 
    } 
} 
+2

使用'tie'寫出<<'健全。 – Yakk

+0

謝謝,它的工作。我完全忽視了我正在處理operator <的事實 – RCO

3

<沒有資格作爲嚴格的弱秩序。所以你的代碼一旦放入地圖就會使用UB。

最簡單的方法寫一個符合<是:

friend auto mytie(const mapPoint& self){ 
    return std::tie(self.X, self.Y); 
} 
friend bool operator<(const mapPoint& lhs, const mapPoint& rhs){ 
    return mytie(lhs)<mytie(rhs); 
} 

如果我們委託<tuple的實現沒有拷貝,並用最大DRY(不要重複自己)。

我發現<手動很容易,但幾十年來容易出錯。