【问题标题】:c++ std::set equalityc++ std::set 相等
【发布时间】:2012-10-31 13:06:41
【问题描述】:

我尝试使用std::set 以便在我的容器中拥有独特的元素。

因为我有 3D 对象:

Class Object3D{  
 private:  
  float x;  
  float y;  
  float z;  
}

(A.x==B.x && A.y==B.y && A.z==B.z)时,这些对象相等。
在 std::set 实现中一个元素 A==B if (!(A < B) && !(B>A)).
我无法进行比较...我试图重载 == 运算符。
当我调用insert(a) 时,我选择了设置容器来比较值。 我正在用 std::vector v 和他的迭代器做类似的事情:

if(!(A).inVector()){
 v.push_back(A);
}

bool inVector(){
 for(itr = v.begin();itr != v.end();itr++){
  if(this->x==(*itr)->x && this->y==(*itr)->y && this->z==(*itr)->z){
   return true;
  }
 }
 return false;
}

为每个对象(10000-100000)检查它的复杂性很高。
有人可以有一个想法吗?

【问题讨论】:

  • stackoverflow.com/questions/12782225/… 有类似的讨论可能对您有所帮助。
  • 您可以提供自己的比较函数,它不一定是小于运算符。不过,它必须服从strict weak ordering。对于比较器函数comp,相等的定义变为!comp(A,B) && !comp(B,A)
  • 是的,请注意 OP:A==B if (!(A<B) && !(B>A)) 应该是 A==B if (!(A<B) && !(B<A))

标签: c++ set compare equals


【解决方案1】:

您需要为您的班级实施严格的弱排序<。最简单的方法是使用tuple提供的字典顺序:

#include <tuple>

class Object3D
{
public:
    bool operator<(Object3D const & rhs) const
    {
        return std::tie(x, y, z) < std::tie(rhs.x, rhs.y, rhs.z);
    }

    // ...
};

【讨论】:

  • 不一定是operator&lt;。也不应该。 OP 是正确的,基于关于 x、y 和 z 坐标的相对重要性的一些任意决定,将一个对象视为小于另一个对象并没有真正意义。
  • @BenjaminLindley:嗯,作为单独排序事物的元组的字典排序是有意义的。而且由于无论如何在 OP 的域上都没有“几何”排序,因此没有混淆的危险。如果您愿意,当然可以专攻std::less&lt;Object3D&gt;。但是你需要弄乱友谊。一次一件事,嗯?
【解决方案2】:

@OP:std::set 是一个独特的有序容器。它需要operator&lt; 或显式传递的比较器,这实现了严格的弱排序。

如果您不想对元素进行排序,不要使用有序容器。如果您只想检测唯一性而不强制排序,可以使用std::unordered_set

【讨论】:

  • 我想这就是我想要的。谢谢
【解决方案3】:

您需要提供一个比较器。你不想实现operator&lt;,我同意这个决定。您不应该仅仅为了满足某些容器的约束而为您的类提供无意义的功能。幸运的是,您不需要operator&lt;。但是您确实需要一个行为类似于operator&lt; 的函数。它不一定意味着一个对象被认为比另一个对象少。它只需要提供严格的弱排序。你可以给它任何你想要的名字。例如:

bool Compare_by_x_then_y_then_z(const Object3D& lhs, const Object3D& rhs)
{
    if (lhs.getX() != rhs.getX()) return lhs.getX() < rhs.getX();
    if (lhs.getY() != rhs.getY()) return lhs.getY() < rhs.getY();
    return lhs.getZ() < rhs.getZ();
}

然后将此函数提供给集合的构造函数:

typedef bool(*compT)(const Object3D&, const Object3D&);
std::set<Object3D,compT> objects(Compare_by_x_then_y_then_z);

【讨论】:

  • 这个解决方案更胜一筹。非常感谢,经过数小时的尝试,今天才在我的工作中使用它
【解决方案4】:

您必须声明运算符

bool operator<(const Object3D& a, const Object3D& b)
{
    if (a.x < b.x) return true;
    if (b.x < a.x) return false;
    if (a.y < b.y) return true;
    if (b.y < a.y) return false;
    if (a.z < b.z) return true;
    if (b.z < a.z) return false;
    return false;
}

这是任意的,但这并不重要。只要 operator

【讨论】:

  • 不,它不能,因为这会改变它在以后的测试之一中返回 true。
【解决方案5】:

必须提供一个比较运算符,因为std::set 需要它来实现它。

一个简单的小于运算符如下所示:

bool Object3D::operator<(const Object3D& other) const {
    if(x != other.x) return x < other.x;
    if(y != other.y) return y < other.y;
    return z < other.z;
}

【讨论】:

  • 你应该将该函数设为常量。
  • 当然可以,但这对积分意味着什么?除了距离之外,一个点如何小于另一个点,但在这种情况下,我的等式约束不匹配。
  • @user1788477:不一定是operator&lt;。您可以创建一个全局函数并将其命名为您想要的任何名称,并将其作为您的集合的附加模板参数提供。因此,这并不一定意味着一个点小于另一个点。它只需要提供某种方式来订购它们。
  • @user1788477 - set 已订购,因此您必须提供一些订购信息。如果您不想订购积分,请不要使用set
猜你喜欢
  • 2015-08-01
  • 2011-05-16
  • 2011-01-19
  • 2014-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-29
  • 1970-01-01
相关资源
最近更新 更多