关于c++名字解析的一个问题:名字空间污染


 编译环境是

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污染原有名字空间

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值