无法使用struct作为键

时间:2016-09-26 02:30:59

标签: c++ struct c++14

我正在尝试使用地图来存储使用坐标x,y作为关键字的地图信息。我无法使用auto迭代器或map.find()正确迭代此映射。它只是不会返回正确的地图值。我正在使用C ++ 14,这是我的代码块:

#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)

它重复了第一个附加价值......我整天都被困住了。有任何想法吗?提前谢谢。

2 个答案:

答案 0 :(得分:4)

你的operator <完全搞砸了。

如果A的X坐标相等且Y坐标相等,则表示A小于B.所以(1,1)&lt; (2,2)是假的,但是(1,1)&lt; (1,1)是真的。难怪地图无法找到合适的条目。

特别是:

  • 因为(1,1)&lt; (2,2)是假的,(1,1)&gt; (2,2)是假的(&gt;正在反驳论证),这意味着(1,1)和(2,2)必须相等!
  • 因为(1,1)&lt; (1,1)为真,(1,1)> (1,1)不可能是真的,因为有一件事不能比另一件事小或大。但它确实如此。

您需要确定点的实际顺序,并在operator <中实现该顺序。例如,你可以说(a,b)&lt; (c,d)如果a&lt; c,或者a = = c且b

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

答案 1 :(得分: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(不要重复自己)。

我觉得手动做<很简单,但几十年来一直容易出错。