簡體   English   中英

C ++比較運算符

[英]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;
    }
};

現在,如果我有一個名為xfoo實例,則可以使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM