免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 7079 | 回复: 25
打印 上一主题 下一主题

[C++] 名字空间、重载候选与lambda。。。 这是g++的bug吗。。。 [复制链接]

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-11-17 19:58 |只看该作者 |倒序浏览
30可用积分
简化后的代码大概是这样:
  1. #include <assert.h>

  2. template<typename T> int f(T const&) { return 0; }
  3. namespace ns {
  4. template<typename T> int f(T const&) { return 1; } }

  5. int main()
  6. {
  7.       using ::ns::f;
  8.       assert(1==::ns::f([]{}));
  9.       assert(1==f(0));
  10. #ifndef NO_AMBIGUOUS
  11.       assert(1==f([]{}));
  12. #endif
  13. }
复制代码
全局和ns名字空间下都有f函数模板。实际代码已经全部砍掉,只留下不同的返回值以方便后面区别。
然后在main里面using ::ns::f 。。。

::ns::f([]{}) 和 f(0) 调用的都是::ns::f。 问题出在f([]{})上。。。
用clang编译调用的也是::ns::f。 而g++编译就报错了。。。

  1. overload_lambda_ambiguous.cpp: In function 'int main()':
  2. overload_lambda_ambiguous.cpp:14:7: error: call of overloaded 'f(main()::<lambda()>)' is ambiguous
  3. overload_lambda_ambiguous.cpp:14:7: note: candidates are:
  4. overload_lambda_ambiguous.cpp:6:26: note: int ns::f(const T&) [with T = main()::<lambda()>]
  5. overload_lambda_ambiguous.cpp:4:26: note: int f(const T&) [with T = main()::<lambda()>]
复制代码
从报错的最后两行来看, 两个f都在重载候选里, 并且都能匹配, 于是ambiguous。
那为什么f(0)又只选择了::ns::f。。。
g++ -DNO_AMBIGUOUS 去掉那行后就正常了。

我用的g++版本比较老。。。 但在某个提供在线编译的网站上用gcc 5.1编译还是有这样的问题。。。 从4.6.3到5.1。。。 都不修复吗。。。

SO...
1. using ::ns::f; 后会hide ::f 对么?
2. 如果对, 那为什么用lambda作为实际参数调用时又没hide? 这是g++的bug吗?
3. 如果不对, f(0) 为什么只选中了::ns::f?

论坛徽章:
89
水瓶座
日期:2014-04-01 08:53:31天蝎座
日期:2014-04-01 08:53:53天秤座
日期:2014-04-01 08:54:02射手座
日期:2014-04-01 08:54:15子鼠
日期:2014-04-01 08:55:35辰龙
日期:2014-04-01 08:56:36未羊
日期:2014-04-01 08:56:27戌狗
日期:2014-04-01 08:56:13亥猪
日期:2014-04-01 08:56:02亥猪
日期:2014-04-08 08:38:58程序设计版块每日发帖之星
日期:2016-01-05 06:20:00程序设计版块每日发帖之星
日期:2016-01-07 06:20:00
2 [报告]
发表于 2015-11-17 20:57 |只看该作者
感觉跟看火星文一样,C++就是强大啊,哈哈。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
3 [报告]
发表于 2015-11-17 21:16 |只看该作者
去 stackoverflow 问问吧,CU 已经没有人气了。

然后去 gcc 提个 bug

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
4 [报告]
发表于 2015-11-17 23:35 |只看该作者
既然你已经写了using ::ns::f,这地方又没涉及到ADL,那么f就应该是::ns::f,想来GCC在这种地方可能实现的有点混乱。

不过报错也不是坏事,最怕的就是不报错给你随便选一个那还不得吐血…………

论坛徽章:
12
2015年辞旧岁徽章
日期:2015-03-03 16:54:1515-16赛季CBA联赛之同曦
日期:2017-03-17 19:13:162016科比退役纪念章
日期:2016-11-07 08:28:12luobin
日期:2016-06-17 17:46:36wusuopu
日期:2016-06-17 17:43:4515-16赛季CBA联赛之福建
日期:2016-01-14 12:49:22程序设计版块每日发帖之星
日期:2015-12-13 06:20:00程序设计版块每日发帖之星
日期:2015-06-08 22:20:00程序设计版块每日发帖之星
日期:2015-06-08 22:20:002015年亚洲杯之科威特
日期:2015-03-24 14:21:272015年迎新春徽章
日期:2015-03-04 09:57:092016科比退役纪念章
日期:2018-04-10 16:20:18
5 [报告]
发表于 2015-11-18 08:34 |只看该作者
估计gcc的支持也还没那么稳定,说不定LZ还真的发现了一个bug,

论坛徽章:
12
2015年辞旧岁徽章
日期:2015-03-03 16:54:1515-16赛季CBA联赛之同曦
日期:2017-03-17 19:13:162016科比退役纪念章
日期:2016-11-07 08:28:12luobin
日期:2016-06-17 17:46:36wusuopu
日期:2016-06-17 17:43:4515-16赛季CBA联赛之福建
日期:2016-01-14 12:49:22程序设计版块每日发帖之星
日期:2015-12-13 06:20:00程序设计版块每日发帖之星
日期:2015-06-08 22:20:00程序设计版块每日发帖之星
日期:2015-06-08 22:20:002015年亚洲杯之科威特
日期:2015-03-24 14:21:272015年迎新春徽章
日期:2015-03-04 09:57:092016科比退役纪念章
日期:2018-04-10 16:20:18
6 [报告]
发表于 2015-11-18 08:34 |只看该作者
估计gcc的支持也还没那么稳定,说不定LZ还真的发现了一个bug,

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
7 [报告]
发表于 2015-11-18 19:14 |只看该作者
回复 2# fender0107401
没有吧? 除了[]{}其他都是C++98的东西吧。。。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
8 [报告]
发表于 2015-11-18 19:16 |只看该作者
回复 3# lost_templar
写e文比较费时。。。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
9 [报告]
发表于 2015-11-18 19:38 |只看该作者
本帖最后由 OwnWaterloo 于 2015-11-18 19:40 编辑

回复 4# windoze

目前还好。。。 反正是写测试时碰到的。。。  即使绕不过去大不了不测了

大概情况是这样。。。

1. 有几个宏。。。
MODULE_NS
MODULE_NS_ENTER
MODULE_NS_LEAVE
如果MODULE_NS没有定义就有一个默认值

2. 后续代码在合适的地方会用这些宏
MODULE_NS_ENTER
... // 这里面定义的一些宏,因为不知道它们会在何处展开,所以会使用 MODULE_NS::detail::some_thing 之类的
MODULE_NS_LEAVE

如果对默认放的名字空间不满意, 就在包含module.hpp前定义这几个宏,把内容放到别的名字空间里去。

3. 测试使用这几个宏

本来应该是分几个cpp单独测的。

  1. // test_ns_global.cpp
  2. #define MODULE_NS
  3. #define MODULE_NS_ENTER
  4. #define MODULE_NS_LEAVE
  5. #include "module.hpp"
复制代码

  1. // test_ns.cpp
  2. #define MODULE_NS ::ns
  3. #define MODULE_NS_ENTER namespace ns {
  4. #define MODULE_NS_LEAVE }
  5. #include "module.hpp"
复制代码

  1. // test_ns_nested.cpp
  2. #define MODULE_NS ::ns::util
  3. #define MODULE_NS_ENTER namespace ns { namespace util {
  4. #define MODULE_NS_LEAVE } }
  5. #include "module.hpp"
复制代码
test_ns_global.cpp, test_ns.cpp, test_ns_nested.cpp 里面显然还要包含一个真正写测试的文件, 不然重复写这么多次不科学。

我觉得这样文件太多很烦。。。 就都放在一个test_ns.cpp里了。

  1. // test_ns.cpp
  2. #ifndef ONLEAVE_TEST_NS_NAME
  3. #include <assert.h>
  4. #include <typeinfo>
  5. // include ...

  6. // 包含自己3次。。。
  7. #define MODULE_NS
  8. #define MODULE_NS_ENTER
  9. #define MODULE_NS_LEAVE
  10. #define MODULE_TEST_NS_NAME global
  11. #include "test_ns.cpp"

  12. #define MODULE_NS ::ns
  13. #define MODULE_NS_ENTER namespace ns {
  14. #define MODULE_NS_LEAVE }
  15. #define MODULE_TEST_NS_NAME ns
  16. #include "test_ns.cpp"

  17. #define MODULE_NS ::ns::util
  18. #define MODULE_NS_ENTER namespace ns { namespace util {
  19. #define MODULE_NS_LEAVE } }
  20. #define MODULE_TEST_NS_NAME nested
  21. #include "test_ns.cpp"

  22. int main() {}
  23. #else /* defined(MODULE_TEST_NS_NAME)*/
  24. // 实际测试用的代码
  25. #endif
复制代码
然后就中招了。。。

如果gcc不报错,但选错了名字空间的话, 测试应该全都能通过(毕竟所有名字空间里的功能都是一样的。。。)。。。
但有测试里面有输出typeid(x).name(), 所以仔细看还是能看出来。。。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
10 [报告]
发表于 2015-11-18 19:46 |只看该作者
本帖最后由 OwnWaterloo 于 2015-11-18 19:47 编辑

回复 4# windoze

module.hpp里面肯定会用C++11的东西, 所以用户也肯定要用C++11, 所以。。。
相比:

  1. #define MODULE_NS ::my::favorite::ns
  2. #define MODULE_NS_ENTER namespace my { namespace favorite { namespace ns {
  3. #define MODULE_NS_LEAVE }}}
  4. #include "module.hpp"
复制代码
用C++11新加的这个(namespace alias?):

  1. #include "module.hpp"
  2. namespace favorite = a::default::explict::and::long::ns;
复制代码
会更方便点?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP