设置<Vec3b>的错误行为

Wrong behaviour of set<Vec3b>

本文关键字:错误 Vec3b lt 设置 gt      更新时间:2023-10-16

我有一组Vec3b来保存可能的RGB像素值。

std::set<cv::Vec3b> used_colors;


但行为怪异:

used_colors.insert(cv::Vec3b(100, 255, 255));
// this returns 1 although (100, 0, 0) is NOT in the set
used_colors.count(cv::Vec3b(100, 0, 0)); 


找到值(100,0,0),因为其他以100开头的值已经插入到集合中。其他值如(80,0,0)找不到。这显然是错误的奇怪行为。


我实现了<像这样的比较运算符:

bool operator <(const cv::Vec3b &a, const cv::Vec3b &b) {
    if(a[0] < b[0])
        return true;
    if(a[0] > b[0]);
        return false;
    if(a[1] < b[1])
        return true;
    if(a[1] > b[1]);
        return false;
    if(a[2] < b[2])
        return true;
    if(a[2] > b[2]);
        return false;
    return false;
}

您的operator<由于几个if语句后的错误分号而损坏。

考虑输入a = Vec3b(100, 255, 255)b = Vec3b(100, 0, 0)。因为两者的R值都是100,所以测试结果是

if(a[0] > b[0]);  // <-- notice the semicolon?

由于后面有分号,函数无条件返回false。由于同样的原因,比较b < a也返回false;并且set::count认为该元素已经存在。

去掉后面的分号,比较运算符就能正常工作了。


与其手动编写所有这些比较来进行字典排序,更简单、更不容易出错的方法是使用std::tie

bool operator<(const cv::Vec3b &a, const cv::Vec3b &b)
{
  return std::tie(a[0], a[1], a[2]) < std::tie(b[0], b[1], b[2]);
}

比较函数填充了,可能是因为在一些if语句之后有;

即使这样,这也比它需要的要复杂得多。std::tie让它变成了一行:

bool operator <(const cv::Vec3b &a, const cv::Vec3b &b) 
{
    return std::tie(a[0], a[1], a[2]) < std::tie(b[0], b[1], b[2]); 
}