如何使用相反的签名坐标键初始化 std::map?

How can I initialize a std::map with opposite signature coordinate keys?

提问人:ModernEraCaveman 提问时间:8/22/2023 更新时间:8/22/2023 访问量:52

问:

对于一些背景信息,我正在尝试使用字典查找创建一个快速的四叉树生成算法。基本概念涉及通过二进制表示将坐标映射到四叉树节点:

struct vec2 { // Test coordinate object
    double x, y; // replacing double with signed int everywhere does not achieve results either
    vec2(const double& x = NULL, const double& y = NULL)
        : x(x), y(y) {}
    friend std::ostream& operator<<(std::ostream& os, vec2 vector)
    {
        return os << "(" << vector.x << ", " << vector.y << ")\n";
    }
    bool operator()(const vec2& lhs, const vec2& rhs) const
    {
        /* TODO: make proper sorting function */
        if ((lhs.x < rhs.x) && (lhs.y < rhs.y)) {
            return true;
        }
        if (std::hypot(lhs.x, lhs.y) < std::hypot(rhs.x, rhs.y)) {
            return true;
        }
        
        return false;
    }
};

std::map<vec2, std::bitset<4>, vec2> nodeLoc = { // quadtree node mapping
            { ( 1, 1), 1000 }, // first quadrant
            { (-1, 1), 0100 }, // second quadrant
            { (-1,-1), 0010 }, // third quadrant
            { ( 1,-1), 0001 }, // fourth quadrant
            { ( 0, 0), 0000 }, 
            { ( 0, 1), 1100 }, // first and second
            { ( 0,-1), 0011 }, // third and fourth
            { ( 1, 0), 1001 }, // first and fourth
            { (-1, 0), 0110 }, // second and third
};

int main() {

    std::cout << nodeLoc[(-1, -1)];

    return 0;
}

main 函数应打印到控制台,但它会打印。映射函数是用 标识的,但我认为 的定义会阻止它们被标识为相同的输入。我尝试创建一个哈希函数来与 一起使用,但最终遇到了类似的问题(尽管略有不同,因为映射与 相同)。00101000(-1, -1)(1, 1)bool operator()std::unordered_map(-1,1)(1,-1)

如何在有符号坐标及其二进制节点表示之间适当地创建映射?

C++ 坐标 std 比较器 stdmap

评论

2赞 Jarod42 8/22/2023
(0, 1)是。。只是(涉及逗号运算符。1{0, 1}
1赞 Jarod42 8/22/2023
以同样的方式,您可能想要 或代替 .bitset"1000"0b10001000
0赞 ModernEraCaveman 8/22/2023
@Jarod42是的,谢谢。我没有意识到将整数放入 as 或只是将它们分别转移到 和 上,使它们成为 的同义词,尽管我应该期望如此。似乎现在我只需要找到一个合适的排序/哈希函数。0001010011001000bitset<4>
0赞 Jarod42 8/22/2023
实际上是(使用八进制(以 8 为基数)。010064
1赞 Jarod42 8/22/2023
词典顺序如何:甚至(C++20)。bool operator()(const vec2& lhs, const vec2& rhs) const { return std::tie(lhs.x, lhs.y) < std::tie(rhs.x, rhs.y);auto operator <=>(const vec2& rhs) const = default

答:

2赞 Jan Schultke 8/22/2023 #1

编译器可以指出代码中的两个关键错误:

没有空引用

warning: converting to non-pointer type 'double' from NULL [-Wconversion-null]
    9 |     vec2(const double& x = NULL, const double& y = NULL)
      |                            ^~~~

首先,你正在做的事情基本上是在代码中。C++ 中没有空引用这样的东西,这似乎是您要创建的。也不是说 a 可以绑定到临时值(临时物化),以便代码编译。const double& x = 0const&

若要解决此问题,请完全删除构造函数,这将生成聚合类型。或者:vec2

// note: don't use default arguments because they would allow initialization
//       with just one argument, which is undesirable
vec2(double x, double y) : x(x), y(y) {}
vec2() : vec2(0, 0) {}

(1, 1)是逗号表达式,而不是构造函数调用

第二个错误是使用以下语法:

warning: left operand of comma operator has no effect [-Wunused-value]
   30 |             { ( 1, 1), 1000 }, // first quadrant
      |                 ^

(1, 1)不做,而是用逗号运算符,其中左边去掉,右边用来调用。您的原始构造函数可以只用一个参数调用,而不是 ,因此可以从 到 进行隐式转换。vec2(1, 1)11vec2(1)explicit1vec2

要解决此问题,请使用 ,其中 inner 等价于 。{ { 1, 1}, 1000 }{ 1, 1}vec2(1, 1)

更多说明

  • 1000是十进制文字;初始化0b1000std::bitset
  • vec2不应是提供给 的函数对象;您可以简单地变成并使用std::mapoperator()operator<std::map<vec2, std::bitset<4>>
    • 或者,定义一个三向比较运算符
  • nodeLoc应该声明为理想状态,而不是(也使用逗号运算符),而是将constnodeLoc[(x, y)]nodeLoc.at({x, y})

请参阅 Compiler Explorer 中的实时示例,其中包含已实现的所有更改