簡體   English   中英

關於std :: less行為的問題

[英]Question about std::less behavior

那里發生了什么?

#include <functional>

namespace A {
    struct Class { };
}

bool operator<(const A::Class& a, const A::Class& b)
{ return false; }

int main()
{
    std::less<A::Class>()(A::Class(), A::Class());
    return 0;
}

編譯好了。 但是,如果我使用。

#include <set>

我有錯誤:

g++     test.cc   -o test
In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/4.5.2/include/g++-v4/bits/stl_tree.h:64:0,
                 from /usr/lib/gcc/x86_64-pc-linux-gnu/4.5.2/include/g++-v4/set:60,
                 from lookup.cc:1:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.2/include/g++-v4/bits/stl_function.h: In member function 'bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = A::Class]':
test.cc:15:49:   instantiated from here
/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.2/include/g++-v4/bits/stl_function.h:230:22: error: no match for 'operator<' in '__x < __y'
make: *** [test] Error 1

該查找失敗的原因是set引入了operator<std::setstd隱藏所有其他的全局命名空間operator<

std::less的實例化中查找<std命名空間內的范圍內發生。 任何operator< std命名空間之外的唯一方法是ADL開始行動,這只發生在最近的封閉命名空間中。

在不包含<set>std命名空間中沒有operator<引入(這可能是依賴於實現的)隱藏了全局operator<因此非ADL查找規則仍然可以找到全局operator<哪個采用A::Class

更正:正如@JohannesSchaub指出的那樣,只有在第一次包含<functional> (其中定義了std::less )之前發生了operator<的聲明時,此分析才是正確的。 實際上,在模板定義中非ADL查找應該可見的非限定id調用的函數的唯一重載是在定義點可見的那些重載。 在定義點和實例化點之間引入的定義應僅對ADL查找可見。 (在一個表達式中,例如x < y候選函數名為operator<被搜索,這是unqualified-id的一種特殊形式。)

就目前而言,重載operator<不應被視為具有或不具有<set> include的候選者,盡管查找規則中的這些極端情況並非總是由所有編譯器正確處理。

operator<應該在namespace A中,否則無法查找。

詳細信息:首先,簡單地從main()調用operator< on兩個Class對象,或者甚至實現自己的less ,無論operator<是否與Class在同一個命名空間中都有效,盡管它應該在同一個命名空間中這就是每個人,包括圖書館的實施者所期望的。 gcc和MSVC 2010(我剛剛測試過)都在其標准庫中包含了幾個額外的operator< ,編譯器之間無法解析。

gcc 4.5.2的錯誤消息具有誤導性。 使用預發行版4.6編譯相同內容,我得到的更具體

In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/4.6.0-alpha20110115/include/g++-v4/bits/stl_tree.h:65:0,
                 from /usr/lib/gcc/x86_64-pc-linux-gnu/4.6.0-alpha20110115/include/g++-v4/set:60,
                 from test.cc:1:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.0-alpha20110115/include/g++-v4/bits/stl_function.h: In member function 'bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = A::Class]':
test.cc:9:42:   instantiated from here
/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.0-alpha20110115/include/g++-v4/bits/stl_function.h:234:22: error: no match for 'operator<' in '__x < __y'
/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.0-alpha20110115/include/g++-v4/bits/stl_function.h:234:22: note: candidates are:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.0-alpha20110115/include/g++-v4/bits/stl_pair.h:205:67: note: template<class _T1, class _T2> bool std::operator<(const std::pair<_T1, _T2>&, const std::pair<_T1, _T2>&)
/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.0-alpha20110115/include/g++-v4/bits/stl_iterator.h:290:46: note: template<class _Iterator> bool std::operator<(const std::reverse_iterator<_Iterator>&, const std::reverse_iterator<_Iterator>&)
/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.0-alpha20110115/include/g++-v4/bits/stl_iterator.h:340:47: note: template<class _IteratorL, class _IteratorR> bool std::operator<(const std::reverse_iterator<_IteratorL>&, const std::reverse_iterator<_IteratorR>&)
/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.0-alpha20110115/include/g++-v4/bits/stl_tree.h:847:70: note: template<class _Key, class _Val, class _KeyOfValue, class _Compare, class _Alloc> bool std::operator<(const std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>&, const std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>&)
/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.0-alpha20110115/include/g++-v4/bits/stl_set.h:712:46: note: template<class _Key, class _Compare, class _Alloc> bool std::operator<(const std::set<_Key, _Compare, _Alloc>&, const std::set<_Key, _Compare, _Alloc>&)
/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.0-alpha20110115/include/g++-v4/bits/stl_multiset.h:695:51: note: template<class _Key, class _Compare, class _Alloc> bool std::operator<(const std::multiset<_Key, _Compare, _Alloc>&, const std::multiset<_Key, _Compare, _Alloc>&)

順便說一下,SunCC(同時使用rw和stlport4)可以干凈地編譯它,甚至可以創建一個可用的std::set<A::Class> <A :: Class>。

您的operator< overload需要與Class位於同一名稱空間中(也就是說,它也需要位於A名稱空間中)。

C ++具有復雜的名稱查找規則。 其中一個更有趣的“功能”是“依賴於參數的查找”或ADL,其中名稱可以在與函數參數關聯的名稱空間中查找。 對於沒有基類且不是嵌套類的類(如Class ,唯一關聯的命名空間是類所在的命名空間。

因此,與Class關聯的唯一命名空間是A ,因此在operator< overload的參數依賴查找期間僅搜索A命名空間。

Charles Bailey的回答很好地解釋了為什么在包含<set>時只能看到問題。

暫無
暫無

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

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