[英]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==
,它是任意對的模板,比較第first
和second
字段。 在四種情況之一中選擇此運算符,即使用TYPE == type1
find
。 但細節有點復雜:
TYPE == type1
實際發生的是(如果我錯了,請糾正我)
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的答案在幾個細節上是不完整的。 那么讓我們為表達式和兩種類型播放編譯器,不是嗎?
cout << (v1 == v2) << endl;
首先,對於type1
和type2
, 非限定名稱查找從main()
函數范圍向外開始,並在全局范圍內找到您自己的operator==
函數。
其次, 依賴於參數的名稱查找 (ADL)從namespace std
找到函數模板operator==
for std::pair
。 實際上,ADL發現了更多std::operator==
函數模板(來自std::vector
和std::string
模板,因為你也包含了那些頭文件)。
注意 :ADL還會找到type2
的匹配項,因為它的基類type1
會將namespace std
添加到其關聯的命名空間集合中。
3.4.2依賴於參數的名稱查找[basic.lookup.argdep]
- 如果T是類類型(包括聯合),則其關聯的類是:類本身; 它所屬的成員,如果有的話; 及其直接和間接基類。 其關聯的名稱空間是其關聯類是成員的名稱空間。
第三,對所有找到的函數模板進行模板參數推導 。 對於type1
,只有std::pair
的函數模板才能在參數推導中存活(並且它將其模板參數推導為分別為std::string
和int
)。 但是,對於type2
,沒有適合的模板參數集,因為type2
不是std::pair
模板的實例化。
第四, 重載決議起作用。 對於type1
,您自己的函數operator==
和std::operator==
function模板具有相同的等級(Exact Match)。 因此,平局決定將選擇您的非模板功能。 對於type2
,只有一個可行的功能,因此重載分辨率不起作用,您的功能將被選中。
結論1 :盡管出於不同的原因, type1
和type2
將給出相同的答案(您的版本被選中)。
cout << (find(vec.begin(), vec.end(), v2) != vec.end()) << endl;
這里我們需要先解決調用find
。 因為你using namespace std;
,非限定名稱查找已找到(沒有雙關語) std::find
,但即使沒有using指令, std::vector
迭代器上的ADL也會找到它。 它會將std::find
的第三個模板參數推斷為type1
或type2
。
在std::find
, std::find
對operator==
的調用。 同樣,將首先執行普通查找。 但是,這發生在namespace std
。 它會找到幾個operator==
函數模板(對於std::vector
, std::string
和std::pair
)。 一旦在非限定名稱查找期間找到一個范圍中的候選者,該名稱查找階段就會停止。
但是,ADL仍在執行中。 請注意,全局命名空間不是type1
的關聯命名空間, 因為它只是 namespace std
類的typedef 。 因此對於type1
,ADL沒有找到任何新內容。 相反, type2
確實將全局命名空間作為其關聯的命名空間,因此在這種情況下ADL將找到您的operator==
function模板。
對於type1
,template-argument-deduction將std::string
和int
作為std::pair
的operator==
function模板的模板參數。 對於type2
,還沒有適合的模板參數集,因為type2
不是std::pair
模板的實例化。
這留下了重載決議。 對於type1
,只有一個可行的函數( std::operator==
template的實例),並且重載解析不起作用。 對於type2
,也只有一個可行的功能(可行,因為它只需要標准的derived-to-base
轉換)。 因此,重載分辨率也沒有發揮作用。
結論2 :對於type1
( std
版本)和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 std
( namespace std
與全局命名空間)找到不同的名稱。
std::pair
有自己的operator==
,它優先於你自己的operator==
。
我認為你最好不要使用find_if而不是find。 它需要一個謂詞,因此您可以將比較器定義為普通函數/仿函數並傳遞它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.