我经常看到人们只覆盖运营商<,而不是>或==。这是否意味着默认情况下,运营商>和operator ==是使用operator< ?
我也经常看到有人写作(见here)
bool operator() (Node const& n1, Node const& n2) const
{
// TODO: your condition
return n1.a < n2.a;
}
operator()在这里意味着什么?这看起来非常违反直觉。
答案 0 :(得分:3)
他们只是覆盖<
的原因是因为默认情况下订购的容器用来比较值,所以他们需要定义来回答这个问题。
#include <set>
struct my_fancy_integer
{
int fancy;
};
// This is all std::set (or any ordered container) needs by default,
// So for an example answer I won't do anything else (as I expect you to
// learn and understand *why* it needs this by default).
bool operator<(const my_fancy_integer& first, const my_fancy_integer& second)
{
return first.fancy < second.fancy;
}
// But I should really also defined the other comparison operators...
// For example, without operator> defined this would fail:
//
// std::set<my_fancy_integer, std::greater<my_fancy_integer>> x;
//
// But since you read documentation for std::set and std::greater you
// understand why this fails: std::set will use std::greater to order
// the values, and std::greater (by default) will try to use operator>.
int main()
{
std::set<my_fancy_integer> x; // okay
}
不,其他运营商没有隐含地定义它(也没有其他任何东西)。在实际应用程序中,如果您已经定义了一个,则应该全部定义它们。
或者,如果<
在语法上对您的类型没有意义,但是对它们进行排序仍然很有价值,请定义一个可用的默认谓词,用户应该将其传递给有序容器的谓词模板参数。
#include <set>
#include <string>
#include <tuple>
struct my_employee
{
std::string name;
int salary;
int yearsEmployed;
};
// Saying one employee is "less" than another doesn't really make sense...
// But I can still give an *ordering* on them:
struct my_employee_ordering
{
bool operator()(const my_employee& first, const my_employee& second) const
{
// I'll just reuse std::tuple's comparison operator, and tie the
// fields of each structure into a tuple to use it. This orders
// by name, salary, then yearsEmployed.
return std::tie(first.name, first.salary, first.yearsEmployed) <
std::tie(second.name, second.salary, second.yearsEmployed);
}
};
int main()
{
// We need to tell std::set how to order employees:
std::set<my_employee, my_employee_ordering> x; // okay
}
operator()
是函数调用运算符。它允许你的对象被“调用”:
struct foo
{
void operator()(int x) { std::cout << x << std::endl; }
};
foo f;
f(5); // calls foo::operator()(5)
答案 1 :(得分:2)
首先,没有。 &lt;的实现不隐式定义==和&gt;。人们倾向于定义&lt;因为标准库使用少于运算符的特定比较来进行列表排序和类似任务。
operator()被称为函数调用运算符。基本上,假设我有一个结构foo如下
struct foo {
int operator()(int a, int b) {
return a+b;
}
};
现在,如果我有一个名为foo
的{{1}}实例,我可以使用x
,它将使用我给出的两个参数调用函数调用运算符(6和5 in这个案例)。函数调用操作符只是用于处理函数之类的结构,可以接受任何数量和类型的参数,甚至不带参数。在您给出的示例中,当包含该函数的对象用作函数调用时,它将比较两个节点对象并返回x(6, 5)
如果第一个小于第二个节点对象,则根据&lt;操作
答案 2 :(得分:1)
定义的最小比较或排序运算符为<
和==
。
其他比较运算符可以根据这些来定义:
operator != -- !operator==
operator >= -- !operator<
operator <= -- operator== || operator <
operator > -- !(operator== || operator <)
boost
库包含将生成所有其他运算符的模板。有关示例,请参阅“less_than_comparable”。
编辑1:
operator()
定义了一个排序操作,通常由排序函数使用。例如,您可以为升序排序定义一个函数,为降序排序定义另一个函数。要进行排序,您可以传递升序函数对象或降序函数对象。
答案 3 :(得分:0)
您所看到的是人们实现特殊用途的仿函数而非通用对象;这是C ++&#34;让你做的事情。但是并没有让你明确做到&#34;。
因此,您看到&#34;运营商&lt;&#34;对于在不需要比较的有序容器中使用函数进行弱排序的情况。该课程仅用于此目的,因此不需要实施比较操作员等。
operator()用于谓词仿函数,以允许对象被称为&#34;#34;以明确的方式:
struct EqualityPredicate {
bool operator()(const Node& lhs, const Node& rhs) const { return lhs == rhs; }
};
EqualityPredicate& equality;
for (Node hay : haystack) {
if(equality(hay, haystack))
doWork(hay);
}
调用equality.operator()(hay,haystack);
答案 4 :(得分:0)
这是常见的任务,您必须为对象重载/重写或定义自定义比较运算符,例如,将它们存储在set / unordered_sets中或将这些对象用作map / unordered_maps中的键。 为此,您必须定义“小于”运算符(<),等于运算符(==)和“哈希”运算符。 C ++允许以不同的方式进行操作。我首选的方法是在对象内部定义它们。因此,您可以更好地了解对象的行为。 我创建的示例在现实世界中可能没有多大意义,但展示了定制行为的概念。
#include<assert.h>
#include<set>
#include<string>
#include<unordered_map>
#include<unordered_set>
#include<map>
using namespace std;
struct Person
{
string name;
unsigned age;
double wage;
Person() :name(""), age(0), wage(0.0) {}
Person(const string& n, unsigned a, double w) :name(n), age(a), wage(w) {}
Person & operator=(const Person& p) {
if (this == &p)
return *this;
this->name = p.name;
this->age = p.age;
this->wage = p.wage;
return *this;
}
// less than oprator for sets
bool operator<(const Person& other) const {
return this->wage < other.wage;
}
// equal oprator for maps
bool operator==(const Person& other)const {
return ((this->name == other.name) && (this->age == other.age));
}
//hash operator for unordered_sets/unordered_maps
size_t operator()(const Person& p) const {
return std::hash<string>()(p.name);
}
};
int main()
{
set<Person> personsSet;
Person a("a", 20, 3000.0), b("b", 30, 2000.0), c("c", 40, 1000.0), d("d", 25, 500.0), e("e", 31, 700.0);
personsSet.insert(a);
assert(personsSet.size() == 1);
personsSet.insert(b);
assert(personsSet.size() == 2);
personsSet.insert(c);
assert(personsSet.size() == 3);
personsSet.insert(d);
assert(personsSet.size() == 4);
personsSet.erase(b);
assert(personsSet.size() == 3);
personsSet.erase(e);
assert(personsSet.size() == 3);
map<Person, string> personsMap;
personsMap.insert({ a, "first" });
personsMap.insert({ b, "second" });
personsMap.insert({ c, "third" });
personsMap.insert({ d, "fourth" });
assert(personsMap.size() == 4);
personsMap[d] = "";
assert(personsMap[d] == "");
personsMap.erase(b);
assert(personsMap.size() == 3);
personsMap.erase(e);
assert(personsMap.size() == 3);
unordered_set<Person, Person> personUset;
personUset.insert(a);
assert(personUset.size() == 1);
personUset.insert(b);
assert(personUset.size() == 2);
personUset.insert(c);
assert(personUset.size() == 3);
auto f = personUset.find(b);
personUset.erase(f);
assert(personUset.size() == 2);
f = personUset.find(e);
assert(f == personUset.end());
unordered_map<Person, int, Person> personUmap;
personUmap[b] = 2;
assert(personUmap.size() == 1);
assert(personUmap[b] == 2);
personUmap[c] = 3;
personUmap[d] = 4;
auto mf = personUmap.find(c);
assert(mf->first == Person({"c", 40, 1000.0}));
assert(mf->second == 3);
assert(personUmap.size() == 3);
personUmap.erase(mf);
assert(personUmap.size() == 2);
personUmap.erase(e);
assert(personUmap.size() == 2);
}