编译环境是
gcc version 4.5.1 (tdm-1)
和
Microsoft Visual Studio 2010 10.0.30319.1 RTMRel
操作系统是
Windows7 旗舰版
问题:
#include <algorithm>
using namespace std;
namespace X
{
struct Y{int v;};
};
bool operator < (X::Y a, X::Y b)
{
return a.v < b.v;
}
int main()
{
X::Y data[5];
sort(data, data+5);
return 0;
}
编译无法通过。
主要错误提示,无法找到对应的operator <。
1.一个直观的感觉是sort在algorithm里有了,在定义里,找不到对应的operator <。
其实不然,因为模板的实例化点不在algorithm里。所以,即使把#include <algorithm>
搬到operator <后是不行的。
2.试图错误重现:
#include <algorithm>
#include <iostream>
using namespace std;
namespace X
{
struct Y{int v;};
};
bool operator < (X::Y a, X::Y b)
{
return a.v < b.v;
}
namespace Z
{
int foo(X::Y a)
{
return a < a;
}
}
int main()
{
X::Y data[5];
cout << Z::foo(data[0]) << endl;
return 0;
}
没有报错
交换operator < 和namespace Z后报错,这很显然。
回想到sort是函数模板,于是把foo改成模板形式:
#include <algorithm>
#include <iostream>
using namespace std;
namespace X
{
struct Y{int v;};
};
namespace Z
{
template<typename T>
int foo(T a)
{
return a < a;
}
}
bool operator < (X::Y a, X::Y b)
{
return a.v < b.v;
}
int main()
{
X::Y data[5];
cout << Z::foo(data[0]) << endl;
return 0;
}
即使改变顺序也不会报错,原因是实例化点在operator <后面。
结论:试图错误重现失败。
3.进一步错误重现:
把gcc中的__insertion_sort copy出来放到namespace Z里,同时包含必要的头文件,对
代码中必要的部分进行修改,但是没有本质上的修改。
但是没有出现期待中的错误。
结论:进一步错误重现失败。
4.使用vc10发现在utility, memory等文件中总共有4个侯选的operator <。
通过把这四个operator <注释掉,没有出现错误。
5.更进一步错误重现:
#include <algorithm>
#include <iostream>
using namespace std;
namespace X
{
struct Y{int v;};
};
namespace Z
{
template<typename T>
struct dummy{};
template<typename T>
bool operator <(dummy<T>, dummy<T>){return 1;}
template<typename T>
int foo(T a)
{
return a < a;
}
}
bool operator < (X::Y a, X::Y b)
{
return a.v < b.v;
}
int main()
{
X::Y data[5];
cout << Z::foo(data[0]) << endl;
return 0;
}
结果:出现期待中的错误。
6.结论:
在同一scope里查找失败时,不会在外一层scop中查找。
7.解决方案1
namespace X
{
struct Y{int v;};
bool operator < (Y a, Y b)
{
return a.v < b.v;
}
};
对某个类型的操作,应该放在该类型所在的scope里,这样可以通过ADL查找到对应的名字。
如果放在该scope的外层,在该scope里的同名的会阻止在外层中的名字解析:名字污染。
8.解决方案2
#include <algorithm>
#include <iostream>
using namespace std;
namespace X
{
struct Y{int v;};
};
bool operator < (X::Y a, X::Y b)
{
return a.v < b.v;
}
int main()
{
X::Y data[5];
bool (*cmp)(X::Y, X::Y) = &operator < ;
sort(data, data+5, cmp);
return 0;
}
很明显,从执行效率,代码优美程度上讲都不如解决方案1。
如果是使用别人的库,原有的compare不满足要求,同时又不希望自己写的cmpare污染原有名字空间