7

创建一个以坐标为键的 std::map 似乎是不可能的。当两个坐标的 (x+y+z) 相同时,地图只会覆盖前一个。例子:

map[Coordinate(1, 0, 0)] = object1;
map[Coordinate(0, 1, 0)] = object2;
map[Coordinate(0, 0, 1)] = object3;

这将导致存在一个带有 1 个元素的 std::map,其中包含object3作为值和Coordinate(0, 0, 1)作为键。我怎样才能防止这种情况,以便它包含所有值?

#pragma once

struct Coordinate {
    double x, y, z;
    Coordinate(double x, double y, double z) : x(x), y(y), z(z) {}

    bool operator<(const Coordinate& coord) const {
     if(x + y + z < coord.x + coord.y + coord.z)
        return true;
     return false;
    }

    bool operator==(const Coordinate& coord) const {
        if(x == coord.x && y == coord.y && z == coord.z)
            return true;
        return false;
    }

    inline bool isInRange(Coordinate coord, int range) const {
        if(pow(coord.x - this->x, 2) + pow(coord.y - this->y, 2) + pow(coord.z - this->z, 2) <= range*range)
            return true;
        return false;
    }
};
4

3 回答 3

8

« std::map 是一个排序的关联容器,包含具有唯一键的键值对。使用比较函数比较对键进行排序。» 来自cppreference

默认比较函数将在对象std::less上使用 operator< 。Key

因此,问题在于operator<Coordinate

bool operator<(const Coordinate& coord) const {
 if(x + y + z < coord.x + coord.y + coord.z)
    return true;
 return false;
}

(1, 0, 0) < (0, 1, 0)是假的,但(0, 1, 0) < (1, 0, 0)也是假的,就目前std::map而言,(1, 0, 0) == (0, 1, 0).

为了将Coordinate对象用作 a 中的键std::map,您需要找到operator<满足您需要的正确的严格弱排序标准 (the )。

正如其他人所说,您可以使用std::tie(在 C++11 中)之类的东西,它首先比较xy然后z像这样:

bool operator<(const Coordinate& coord) const {
    if(x < coord.x) return true;
    if(x > coord.x) return false;
    //x == coord.x
    if(y < coord.y) return true;
    if(y > coord.y) return false;
    //x == coord.x && y == coord.y
    if(z < coord.z) return true;
    if(z > coord.z) return false;
    //*this == coord
    return false;
}
于 2013-08-02T14:57:25.847 回答
2

您的运算符 < 必须工作,以便所有可能的坐标都可以以稳定的顺序放置。如果添加这些值,则有几种坐标组合彼此无法区分。

尝试这个

friend bool operator < (const Coordinate& left, const Coordinate& right)
{
    if (left.z < right.z)
    {
        return true;
    }
    else if (right.z < left.z)
    {
        return false;
    }
    else if (left.y < right.y)
    {
        return true;
    }
    else if (right.y < left.y)
    {
        return false;
    }
    else if (left.x < right.x)
    {
        return true;
    }
    else /* (right.x < left.x) */
    {
        return false;
    }
}
于 2013-08-02T15:02:24.017 回答
-1

出于比较的目的, astd::map会将两个对象aandb视为相同的 if !(a < b) && !(b < a)。你operator<创造的正是这样的模棱两可。首先,您插入 with(1, 0, 0)作为键。接下来,您将插入并比较(0, 1, 0). 但是,使用您拥有的运算符,(1, 0, 0) < (0, 1, 0)返回false,因此(0, 1, 0) < (1, 0, 0),两个坐标映射到同一个键。

于 2013-08-02T15:01:29.210 回答