那里发生了什么?
#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;
}
Run Code Online (Sandbox Code Playgroud)
编译好了.但是,如果我使用.
#include <set>
Run Code Online (Sandbox Code Playgroud)
我有错误:
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
Run Code Online (Sandbox Code Playgroud)
CB *_*ley 11
查找失败的原因是在命名空间中set引入了隐藏所有其他全局的operator<for .std::setstdoperator<
<实例化中的查找std::less发生在std命名空间内的范围内.命名空间的任何operator<外部std变得可见的唯一方法是ADL开始行动,这只发生在最近的封闭命名空间中.
如果不包括<set>,没有operator<引入(这是可能实现有关)在std隐藏的全局命名空间operator<,因此非ADL查找规则仍然可以找到全球operator<内搭A::Class.
更正:正如@JohannesSchaub指出的那样,只有在首次包含operator<之前发生的声明<functional>(在何处std::less定义)时,此分析才是正确的.实际上,在模板定义中非ADL查找应该可见的非限定id调用的函数的唯一重载是在定义点可见的那些重载.在定义点和实例化点之间引入的定义应仅对ADL查找可见.(在搜索的x < y候选函数等表达式operator<中搜索,这是unqualified-id的一种特殊形式.)
就目前而言,重载operator<不应被视为有或没有<set>包含的候选者,尽管查找规则中的这些极端情况并非总是由所有编译器正确处理.
这operator<应该namespace A也是,否则就无法查找.
详细信息:首先,简单地调用operator<两个Class对象main(),或者甚至实现自己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>&)
Run Code Online (Sandbox Code Playgroud)
顺便说一句,SunCC(同时包含rw和stlport4)可以完整地编译它,甚至创建一个可用的std::set<A::Class>.