制作一个以坐标为键的std::映射

Make an std::map with a coordinate as key

本文关键字:std 映射 一个以 坐标      更新时间:2023-10-16

创建一个以坐标为键的std::映射似乎是不可能的。当两个坐标的(x+y+z)相同时,贴图将覆盖上一个坐标。示例:

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

这将导致出现一个std::map,其中包含1个元素,其中包含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;
    }
};

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

默认的比较函数是CCD_ 3,它将使用运算符<在CCD_ 4对象上。

因此,问题在于Coordinate:的operator<

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)

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

正如其他人所说,您可以使用类似std::tie(在C++11中)的东西,它将首先比较x,然后比较y,然后比较像这样的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;
}

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

试试这个

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

为了进行比较,如果!(a < b) && !(b < a),则std::map会将两个对象ab视为相同对象。您的operator<正是造成了这种歧义。首先插入(1, 0, 0)作为密钥。接下来,您将插入并比较(0, 1, 0)。但是,对于现有操作符,(1, 0, 0) < (0, 1, 0)返回false(0, 1, 0) < (1, 0, 0)也返回,因此两个坐标映射到同一个关键点。