簡體   English   中英

find()使用重載運算符==

[英]find() using overloaded operator==

我嘗試使用重載的運算符==()在向量中找到一個元素。 但是,如果在以下代碼中使用type1 ,則輸出為1和0(未找到)。 使用type2給出1和1.環境是Xubuntu 12.04和g ++版本4.6.3。

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

typedef pair<string, int> type1;
struct type2: public type1 {};
#define TYPE type1

bool operator== (const TYPE& lhs, const TYPE& rhs) {
    return lhs.first == rhs.first;
}

int main()
{
    vector<TYPE> vec;
    TYPE v1, v2;

    v1.first = "abc"; v1.second = 1; vec.push_back(v1);
    v2.first = "abc"; v2.second = 2;

    cout << (v1 == v2) << endl;
    cout << (find(vec.begin(), vec.end(), v2) != vec.end()) << endl;
}

std::pair在命名空間std有默認的operator== ,它是任意對的模板,比較第firstsecond字段。 在四種情況之一中選擇此運算符,即使用TYPE == type1 find 但細節有點復雜:

TYPE == type1實際發生的是(如果我錯了,請糾正我)

  • for v1 == v2 ADL( Argument Dependent Name Lookup )用於在std查找operator== ,這意味着此運算符被添加到正常的重載集中。 但是,當前轉換單元中的非模板版本仍然優先於模板operator== from std
  • std::find調用在std實例化,因此查找operator==直接在std啟動。 它找到一個匹配(不使用ADL!),因此不會搜索包含OP自己的運算符的封閉范圍。

對於TYPE == type2

  • v1 == v2很簡單 - 直接在封閉的命名空間中找到operator==
  • std::find也在std實例化,但是主范圍中的自定義運算符被添加到使用ADL的重載決策集中,然后發現它比std更具體。

@AlexanderGessler的答案在幾個細節上是不完整的。 那么讓我們為表達式和兩種類型播放編譯器,不是嗎?

表達1

cout << (v1 == v2) << endl;

首先,對於type1type2非限定名稱查找main()函數范圍向外開始,並在全局范圍內找到您自己的operator==函數。

其次, 依賴於參數的名稱查找 (ADL)從namespace std找到函數模板operator== for std::pair 實際上,ADL發現了更多std::operator==函數模板(來自std::vectorstd::string模板,因為你也包含了那些頭文件)。

注意 :ADL還會找到type2的匹配項,因為它的基類type1會將namespace std添加到其關聯的命名空間集合中。


3.4.2依賴於參數的名稱查找[basic.lookup.argdep]

- 如果T是類類型(包括聯合),則其關聯的類是:類本身; 它所屬的成員,如果有的話; 及其直接和間接基類。 其關聯的名稱空間是其關聯類是成員的名稱空間。


第三,對所有找到的函數模板進行模板參數推導 對於type1 ,只有std::pair的函數模板才能在參數推導中存活(並且它將其模板參數推導為分別為std::stringint )。 但是,對於type2 ,沒有適合的模板參數集,因為type2不是std::pair模板的實例化。

第四, 重載決議起作用。 對於type1 ,您自己的函數operator==std::operator== function模板具有相同的等級(Exact Match)。 因此,平局決定將選擇您的非模板功能。 對於type2 ,只有一個可行的功能,因此重載分辨率不起作用,您的功能將被選中。

結論1 :盡管出於不同的原因, type1type2將給出相同的答案(您的版本被選中)。

表達2

cout << (find(vec.begin(), vec.end(), v2) != vec.end()) << endl;

這里我們需要先解決調用find 因為你using namespace std; ,非限定名稱查找已找到(沒有雙關語) std::find ,但即使沒有using指令, std::vector迭代器上的ADL也會找到它。 它會將std::find的第三個模板參數推斷為type1type2

std::findstd::findoperator==的調用。 同樣,將首先執行普通查找。 但是,這發生在namespace std 它會找到幾個operator==函數模板(對於std::vectorstd::stringstd::pair )。 一旦在非限定名稱查找期間找到一個范圍中的候選者,該名稱查找階段就會停止。

但是,ADL仍在執行中。 請注意,全局命名空間不是type1的關聯命名空間, 因為它只是 namespace std的typedef 因此對於type1 ,ADL沒有找到任何新內容。 相反, type2確實將全局命名空間作為其關聯的命名空間,因此在這種情況下ADL將找到您的operator== function模板。

對於type1 ,template-argument-deduction將std::stringint作為std::pairoperator== function模板的模板參數。 對於type2 ,還沒有適合的模板參數集,因為type2不是std::pair模板的實例化。

這留下了重載決議。 對於type1 ,只有一個可行的函數( std::operator== template的實例),並且重載解析不起作用。 對於type2 ,也只有一個可行的功能(可行,因為它只需要標准的derived-to-base轉換)。 因此,重載分辨率也沒有發揮作用。

結論2 :對於type1std版本)和type2 (你的版本),你會得到不同的結果。

摘要

僅僅因為這些事情在不同的命名空間中有多個重載會變得非常棘手,這里是一個帶有神聖三位一體的摘要表(名稱查找,參數推導和重載解析)。 對於每個階段,對於每個階段,我都列出了該階段之后的幸存候選人。 底行顯示被調用的函數。

表達1

+---------------------+-----------------+-----------------+
| phase               | type1           | type2           |
+---------------------+-----------------+-----------------+
| unqualified lookup  |    ::operator== |    ::operator== |
| ADL                 | std::operator== | std::operator== |
+---------------------+-----------------+-----------------+
| argument deduction  |    ::operator== |    ::operator== |
|                     | std::operator== |                 |
+---------------------+-----------------+-----------------+
| overload resolution |    ::operator== |    ::operator== |
+---------------------+-----------------+-----------------+

表達2

+---------------------+-----------------+-----------------+
| phase               | type1           | type2           |
+---------------------+-----------------+-----------------+
| unqualified lookup  | std::operator== | std::operator== |
| ADL                 |                 |    ::operator== |
+---------------------+-----------------+-----------------+
| argument deduction  | std::operator== |    ::operator== |
+---------------------+-----------------+-----------------+
| overload resolution | std::operator== |    ::operator== |
+---------------------+-----------------+-----------------+

請注意,非限定查找根據其開始的范圍(全局范圍內的函數范圍與命名空間范圍)查找不同的名稱,並且ADL類似地根據被視為關聯的namespace stdnamespace std與全局命名空間)找到不同的名稱。

std::pair有自己的operator== ,它優先於你自己的operator==

我認為你最好不要使用find_if而不是find。 它需要一個謂詞,因此您可以將比較器定義為普通函數/仿函數並傳遞它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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