2017-02-03 76 views
3

我有點不解,爲什麼預期下面的代碼是不工作...這張地圖有什麼問題?

#include <iostream> 
#include <map> 

struct Foo { 
    int x,y,z; 
    Foo(int x,int y,int z) : x(x),y(y),z(z) {} 
    bool operator<(const Foo& other) const { 
     if (x > other.x) return false; 
     if (y > other.y) return false; 
     if (z > other.z) return false; 
     return true; 
    } 
    bool operator==(const Foo& other) const { 
     if (other.x != x) return false; 
     if (other.y != y) return false; 
     if (other.z != z) return false; 
     return true; 
    } 
}; 

int main() { 
    Foo f(1,2,3); 
    std::map<Foo,double> map; 
    map[f] = 1.0; 
    std::cout << map[f] << "\n"; 
} 

它打印0而不是1。我做錯了什麼?這裏還

代碼:http://ideone.com/fork/HMwPQ7

+7

您在MyMap模板參數中鍵/值的反轉是_evil_! – YSC

+7

@YSC as就是不會拋出的'at'函數......雷區代碼,就是這個代碼片段! – Quentin

+0

@YSC因爲答案沒有提到那個邪惡,我允許自己編輯它。它是一個從真正的代碼,其中'key'是一個參數包遺留下來的,所以我不知道任何比扭轉鍵/值 – user463035818

回答

4

Foo::operator <沒有定義由std::map所需的strict weak ordering
特別地,給定兩個相同的Foos和b,當它們都應該是假的時,a < bb < a都是正確的。
由於您違反了std::map的合同,行爲未定義。

+0

運行轉發'[]''到[]'和'在()''來模仿它的接口使用啓用了調試功能的STL將會或多或少地告訴你這個問題。 –

+0

@Dan it will?我必須嘗試一下:) /編輯:'_GLIBCXX_DEBUG'不會削減它。這是關於MSVC的STL嗎? – Quentin

+1

我認爲這是「嚴*弱*排序,不只是‘嚴格的順序’。 – Nawaz

8

這是因爲你的operator<已經實施不正確。下面是正確的版本:

bool operator<(const Foo& other) const { 
    if (x != other.x) return x < other.x; 
    else if (y != other.y) return y < other.y; 
    return z < other.z; 
} 

,基本上說,如果x相等,則比較y,如果太等於,然後比較z

閱讀Strict Weak Ordering

更短的實現可能是這樣的:

bool operator<(const Foo& other) const { 
    return std::tie(x, y,z) < std::tie(other.x, other.y, other.z); 
} 

希望有所幫助。

+0

之間。'的std :: tie'更好!甚至'STD :: tuple <>'用於成員數據 –

+2

@Dan:'std :: tie'只是一個友好的函數,用於創建* references的std :: tuple實例(即不需要複製)。 – Nawaz

+0

FYI在'operator <'impl中用'> ='''''也可以做到這一點。 – YSC