[英]C++ comparison operators
我經常看到人們只覆蓋運算符<,而不是>或==。 這是否意味着默認情況下,operator>和operator ==是使用operator <實現的?
我也經常看到人們寫作(請參閱此處 )
bool operator() (Node const& n1, Node const& n2) const
{
// TODO: your condition
return n1.a < n2.a;
}
那么operator()在這里是什么意思? 似乎很違反直覺。
它們僅覆蓋<
的原因是因為默認情況下,這是有序容器用來比較值的東西,因此,它們僅需定義即可回答問題。
#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()
是函數調用operator 。 它允許您的對象被“調用”:
struct foo
{
void operator()(int x) { std::cout << x << std::endl; }
};
foo f;
f(5); // calls foo::operator()(5)
首先,沒有。 <的實現不會隱式定義==和>。 人們傾向於定義<,因為標准庫使用小於運算符的比較來進行列表排序和類似任務。
operator()稱為函數調用運算符。 基本上,假設我有一個struct foo如下
struct foo {
int operator()(int a, int b) {
return a+b;
}
};
現在,如果我有一個名為x
的foo
實例,則可以使用x(6, 5)
,它將使用我給出的兩個參數(在本例中為6和5)調用函數調用運算符。 函數調用運算符僅用於處理類似於函數的結構,並且可以采用任意數量和類型的參數,甚至不采用任何參數。 在您給出的示例中,當將包含該函數的對象用作函數調用時,它將比較兩個節點對象,如果根據<運算符,第一個小於第二個,則返回true
。
定義的最小比較或排序運算符為<
和==
。 其他比較運算符可以根據以下定義:
operator != -- !operator==
operator >= -- !operator<
operator <= -- operator== || operator <
operator > -- !(operator== || operator <)
boost
庫包含將生成所有其他運算符的模板。 有關示例,請參見“ less_than_comparable”。
編輯1:
operator()
定義了排序操作,通常由排序函數使用。 例如,您可以為升序定義一個函數,為降序定義另一個函數。 要進行排序,您可以傳遞升序功能對象或降序功能對象。
您看到的是實現專用功能的人,而不是通用對象。 在這種情況下,C ++會“讓您去做”,但不會“讓您顯式去做”。
因此,對於在不需要比較的有序容器中使用函數進行弱排序的情況,您會看到“ operator <”的重載。 該類僅用於此目的,因此不需要實現比較運算符等。
operator()用於謂詞函子,以明確地允許“調用”對象:
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);
}
調用equal.operator()(hay,haystack);
這是常見的任務,您必須為對象重載/重寫或定義自定義比較運算符,例如將它們存儲在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);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.