简体   繁体   English

如何在 C++ 中使用自定义类型作为映射的键?

[英]How can I use a custom type as key for a map in C++?

I am trying to assign a custom type as a key for std::map .我正在尝试将自定义类型分配为std::map的键。 Here is the type which I am using as key:这是我用作键的类型:

struct Foo
{
    Foo(std::string s) : foo_value(s){}

    bool operator<(const Foo& foo1) {   return foo_value < foo1.foo_value;  }

    bool operator>(const Foo& foo1) {   return foo_value > foo1.foo_value;  }
    
    std::string foo_value;
};

When used with std::map , I am getting the following error:std::map一起使用时,出现以下错误:

error C2678: binary '<' : no operator found which takes a left-hand operand of type 'const Foo' (or there is no acceptable conversion) c:\program files\microsoft visual studio 8\vc\include\functional 143

If I change the struct to the one below, everything works:如果我将struct更改为下面的struct ,则一切正常:

struct Foo
{
    Foo(std::string s) : foo_value(s)   {}

    friend bool operator<(const Foo& foo,const Foo& foo1) { return foo.foo_value < foo1.foo_value;  }

    friend bool operator>(const Foo& foo,const Foo& foo1) { return foo.foo_value > foo1.foo_value;  }
    
    std::string foo_value;
};

Nothing changed, except that the operator is overloaded as friend .除了操作符被重载为朋友之外,没有任何改变。 Why does my first code not work?为什么我的第一个代码不起作用?

I suspect you need我怀疑你需要

bool operator<(const Foo& foo1) const;

Note the const after the arguments, this is to make "your" (the left-hand side in the comparison) object constant.注意参数后面的const ,这是为了使“您的”(比较中的左侧)对象保持不变。

The reason only a single operator is needed is that it is enough to implement the required ordering.只需要一个运算符的原因是它足以实现所需的排序。 To answer the abstract question "does a have to come before b?"回答抽象的问题“a 必须在 b 之前出现吗?” it is enough to know whether a is less than b.知道 a 是否小于 b 就足够了。

It's probably looking for const member operators (whatever the correct name is).它可能正在寻找 const 成员运算符(无论正确的名称是什么)。 This works (note const):这有效(注意常量):

bool operator<(const Foo& foo1) const { return foo_value < foo1.foo_value;}

EDIT: deleted operator> from my answer as it was not needed (copy/paste from question) but it was attracting comments :)编辑:从我的答案中删除了operator>因为它不需要(从问题中复制/粘贴)但它吸引了评论:)

Note: I'm 100% sure that you need that const because I compiled the example.注意:我 100% 确定您需要该const,因为我编译了示例。

Could you please elaborate on this? 你能详细说明一下吗? Why if you make the member const (which as far as I know means that it can't change object's state - eg modify private variables) guarantees that "your" will be the left-hand side? 为什么如果你使成员const(据我所知,它意味着它不能改变对象的状态 - 例如修改私有变量)保证“你的”将是左侧?

I don't yet have the rep to comment on this. 我还没有代表对此发表评论。

const does not magically ensure that "your" will be the left hand side. const并没有神奇地确保“你的”将是左手边。 The poster was saying that the left hand side (ie x in x < y) is the object on which the comparison is being called. 海报说左手边(即x <y中的x)是调用比较的对象。 Just as you protect y's members from change with the const on the argument to operator<, you also want to protect x's members from change with the const at the end of the method signature. 正如您使用运算符<的参数上的const保护y的成员免受更改一样,您还希望保护x的成员不受方法签名末尾的const的更改。

Note the const after the arguments, this is to make "your" (the left-hand side in the comparison) object constant. 注意参数后面的const,这是使“你的”(比较中的左侧)对象不变。

Could you please elaborate on this? 你能详细说明一下吗? Why if you make the member const (which as far as I know means that it can't change object's state - eg modify private variables) guarantees that "your" will be the left-hand side? 为什么如果你使成员const(据我所知,它意味着它不能改变对象的状态 - 例如修改私有变量)保证“你的”将是左侧?

The other answers already solve your problem, but I'd like to offer an alternative solution.其他答案已经解决了您的问题,但我想提供一个替代解决方案。 Since C++11 you can use a lambda expression instead of defining operator< for your struct .C++11 开始,您可以使用lambda 表达式而不是为您的struct定义operator< ( operator> is not needed for your map to work.) Providing a lambda expression to the constructor of a map has certain advantages: (您的映射不需要operator> 。)为映射的构造函数提供 lambda 表达式具有某些优点:

  • I find the declaration of a lambda expressions to be simpler and less error-prone than that of operators.我发现 lambda 表达式的声明比运算符的声明更简单且不易出错。
  • This approach is especially useful if you can't modify the struct that you want to store in your map.如果您无法修改要存储在地图中的struct ,则此方法特别有用。
  • You can provide different comparison functions for different maps that use your struct as key.您可以为使用您的struct作为键的不同映射提供不同的比较函数。
  • You can still define operator< differently and use it for a different purpose.您仍然可以以不同的方式定义operator<并将其用于不同的目的。

As a result, you can keep your struct as short as follows:因此,您可以保持struct简短,如下所示:

struct Foo {
    Foo(std::string s) : foo_value(s) {}
    std::string foo_value;
};

And your map can then be defined in the following way:然后可以通过以下方式定义您的地图:

int main() {
    auto comp = [](const Foo& f1, const Foo& f2) { return f1.foo_value < f2.foo_value; };
    std::map<Foo, int, decltype(comp)> m({ {Foo("b"), 2}, {Foo("a"), 1} }, comp);
    // Note: To create an empty map, use the next line instead of the previous one.
    // std::map<Foo, int, decltype(comp)> m(comp); 

    for (auto const &kv : m)
        std::cout << kv.first.foo_value << ": " << kv.second << std::endl;

    return 0;
}

Output:输出:

a: 1一:1
b: 2乙:2

Code on Ideone Ideone 上的代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM