std :: map密钥类必须满足哪些要求才能成为有效密钥?


75

我想将给定类的对象映射到另一个类的对象。但是,我想用作键的类不是我编写的,它很简单struct,只有几个值。std :: map对其内容进行排序,我想知道它是如何执行的,是否可以将任何任意类用作键,或者是否需要定义一组需求(操作符和其他内容)。

如果是这样,我可以为实现操作符映射使用的类创建一个包装器。我只需要知道我首先需要实现的内容,而在网上找到的类的引用都没有指定它们。

Answers:


67

密钥所需要的只是可复制和可分配。映射中的顺序由模板的第三个参数(以及构造函数的参数(如果使用))定义。该 默认std::less<KeyType>,其默认为<运营商,但没有规定使用默认值。只需编写一个比较运算符(最好是一个功能对象):

struct CmpMyType
{
    bool operator()( MyType const& lhs, MyType const& rhs ) const
    {
        //  ...
    }
};

请注意,它必须定义严格的顺序,即如果CmpMyType()( a, b )返回true,则CmpMyType()( b, a )必须返回false,并且如果两个都返回false,则将元素视为相等(同一等效类的成员)。


+1实际上,这是可复制和可分配的,这是真正的要求。
juanchopanza 2011年

为什么是“最好是作为功能对象”。为什么不以运算符<作为候选类?诚然,OP无法控制类,因此无法添加运算符,但就我而言,这是可能的。添加比较运算符是否不受欢迎?如果是,为什么?
nurdglaw

2
@nurdglaw最近我看了一个谈话,其中一位专家正在operator<为每个班级提供一个。他以椅子为例。您可以按身高,腿数或什至颜色对它们进行排序,但是您选择的选项完全是任意的,实际上椅子没有自然的排序,而是容器必须选择椅子的方式订购。往往一个operator<似乎是显而易见的选择真的是刚一出来的许多可能性,因此不属于入级....沿着这条线的东西是他的推理。
great_prime_is_463035818

@nurdglaw无论如何,可能是“最好是函数对象”指的是其他替代方案:(命名为)成员方法或自由函数
maximum_prime_is_463035818

我把它读作<<如果operator <std::less没有为你做它,然后写一个比较函数作为一个额外的参数给的std ::地图模板声明。如果执行比较器函数,则最好将其声明为函子对象>>这样做函子对象的原因是,在编译时将对象实例优化,而函数指针实际上存在于map对象中而且要优化起来要困难得多。
吉姆·泰勒

24

您需要定义operator <,例如这样:

struct A
{
  int a;
  std::string b;
};

// Simple but wrong as it does not provide the strict weak ordering.    
// As A(5,"a") and A(5,"b") would be considered equal using this function.
bool operator<(const A& l, const A& r )
{
  return ( l.a < r.a ) && ( l.b < r.b );
}

// Better brute force.
bool operator<(const A& l, const A& r )
{ 
    if ( l.a < r.a )  return true;
    if ( l.a > r.a )  return false;

    // Otherwise a are equal
    if ( l.b < r.b )  return true;
    if ( l.b > r.b )  return false;

    // Otherwise both are equal
    return false;
}

// This can often be seen written as
bool operator<(const A& l, const A& r )
{
   // This is fine for a small number of members.
   // But I prefer the brute force approach when you start to get lots of members.
   return ( l.a < r.a ) ||
          (( l.a == r.a) && ( l.b < r.b ));
}

1
那是一个糟糕的比较运算符。
Kerrek SB 2011年

1
这不仅可怕,而且是错误的。它没有提供地图容器所需的“严格弱排序”。上面提供了蛮力版本来补偿。比较A(5,“ A”)和A(5,“ B”)之间的区别
Martin York

正确,我想发布一个简单的示例并加以修正。感谢Martin修改示例。
2011年

4

答案实际上是在您链接的参考中“比较”模板参数的描述下。

唯一的要求是Compare(默认为less<Key>,默认为operator<用于比较键)必须为“严格弱排序”。


2

set:相同:该类必须本着“小于”的精神进行严格的排序。重载相应的operator<,或提供一个自定义谓词。任何两个对象ab对于这两个对象,!(a<b) && !(b>a)将被视为相等。

映射容器实际上将按该顺序提供的顺序保留所有元素,这就是您可以通过键值实现O(log n)查找和插入时间的方式。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.