免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: OwnWaterloo

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

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2015-11-18 19:50 |显示全部楼层
回复 4# windoze
用了一阵C++11。。。 一个字爽。。。 两个字好爽。。。 三个字十分爽。。。
当然也遇见不少坑。。。 绝大部分应该都是我本地环境太搓。。。 除了这个疑似bug。。。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2015-11-19 00:04 |显示全部楼层
回复 5# VIP_fuck

看过喵叔的回复我越发感觉这就是个bug了

论坛徽章:
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
发表于 2015-11-19 13:26 |显示全部楼层
回复 7# OwnWaterloo

我就是看见这个[]{}才晕菜啊。。。  

论坛徽章:
43
15-16赛季CBA联赛之四川
日期:2018-10-13 23:26:5015-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:36程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
发表于 2015-11-19 17:17 |显示全部楼层
回复 12# OwnWaterloo

的确可能是个bug,GCC的ADL之前很长一段时间里都有问题,这次又是一个Name lookup的问题……

不过话说回来,在代码里写using namespace的人都应该拉出去TJJTDS

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2015-11-19 22:12 |显示全部楼层
本帖最后由 OwnWaterloo 于 2015-11-19 22:13 编辑

回复 13# fender0107401

这个是匿名函数。

  1. #include <assert.h>
  2. int main(int argc, char* argv[])
  3. {
  4.       auto add = [](int a, int b) { return a+b; };
  5.       assert(add(1,2)==3);
  6. }
复制代码
有参数列表后会不会熟悉点了。。。


如果不需要参数就可以省略括号

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main(int argc, char* argv[])
  4. {
  5.       atexit([](void){ printf("(void)\n");  });
  6.       atexit([](    ){ printf("()\n");      });
  7.       atexit([]      { printf("omitted\n"); });
  8. }
复制代码
[]{}就是一个接受0个参数并且不做任何事的函数。。。


因为函数可以随处写了,于是就有一个写在顶层的函数不具备的功能。 []和那个功能有关。。。

写在顶层的函数,除了参数之外, 只要有相应的声明还可以访问其他的函数或变量。 这些函数或变量的生命周期都差不多是整个程序执行期间。

而匿名函数除了参数和静态生命周期的函数变量之外, 可以访问一些其他函数的局部变量。
比如前面的argc和argv, 还有add也是main的局部变量。

既然是局部变量, 它的生命周期就会更短。 并且c++也没有垃圾回收, 于是对局部变量的访问就保守一点。。。
[]中就是用来显式地控制函数体{}中可以访问哪些非参数中的变量, 以及以什么形式访问。。。。

[]不允许访问任何非参数非静态生命周期的东西。 除此之外最简单的形式就是[=]和[&]:
  1. #include <assert.h>
  2. #include <stdio.h>
  3. int main(int argc, char* argv[])
  4. {
  5.       int v = 0;
  6.       auto byval = [=]/* () -> const int* */{ return &v; };
  7.       assert(byval() != &v);
  8.       int v1 = *byval();    assert(v1==0);
  9.       v = 1;
  10.       int v2 = *byval();    assert(v2==0);

  11.       int r = 0;
  12.       auto byref = [&]/* () -> int* */{ return &r; };
  13.       assert(byref() == &r);
  14.       int r1 = *byref();    assert(r1==0);
  15.       r = 1;
  16.       int r2 = *byref();    assert(r2==1);
  17. }
复制代码
byval 以[=]的形式访问(捕获)了不是参数也不是静态变量,而是main的局部变量的v。 [=]允许随意访问。。。 要访问argc,argv也是可以的。
byval创建之后, 它里面的v是外面的v的复制([=]中等号=借用了赋值的含义)。
byref 以[&]的形式捕获了r。 两者是同一个整数变量。 ([&]中的&借用了取地址的含义)。
注释里面是返回类型的写法, 在编译器可以推导出来时可以省略。

总之, 这和其他语言里面的匿名函数以及写在顶层的函数没有太大的区别。。。   参数列表,函数体,返回类型(位置稍微有点变动)。。。
区别最大的应该就是[]了。
其他大部分语言都有垃圾回收, 所以不太需要这个东西。
c++没有, 于是就把管理生命周期的责任再次推给程序员了

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2015-11-19 22:14 |显示全部楼层
回复 14# windoze

经常随手一个using namespace std; 。。。 要被tjjtds了

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
发表于 2015-11-20 00:56 |显示全部楼层
楼上两个 tjjtds 都暴露年龄了

另外,这说不定是个 feature

论坛徽章:
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
发表于 2015-11-20 16:25 |显示全部楼层
回复 15# OwnWaterloo

我猜就是那个东西。

最近一直弄Lua,发现匿名函数是函数式编程里面的东西,然后还有闭包。据说匿名函数和闭包是函数式编程的关键。

但是我对函数式编程那套没感觉,总是习惯OOP的方式,看什么都是对象。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2015-11-20 19:24 |显示全部楼层
本帖最后由 OwnWaterloo 于 2015-11-20 19:24 编辑

回复 18# fender0107401

lua可以@这货看看 @starwing83
"object is poor man's closure"
当然也有不少人认为反过来说才成立

论坛徽章:
4
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:11
发表于 2016-01-05 17:42 |显示全部楼层
@OwnWaterloo太过分了,下次发帖的时候上微信跟我说一声啊,这问题我知道。

首先,我没看标准,所以这是不是bug我不知道,但是,从实现的角度上来说,按照旧的标准解释,这个行为是合理的。

为什么呢?这就需要看闭包到底是什么了。闭包是一个对象,确切的说,是一个函数对象(Functor),也就是说,闭包实际上是一个匿名的,实现了operator()的一个struct的一个实例而已,问题就在于这个实例是在哪儿声明的。

你using 了::ns::f,那么这两个函数都参与了重载,这个OK,然后,你调用了::ns::f([]{}),那么,ns::f这个模版关于这个匿名类的对应实例被特化出来了,然后调用了f(0),则int ::f(int)被特化出来了。现在问题是第三个调用了。

假设C++11对目前的ADL规则没有打补丁,那么,如果存在int ::f(main()::lambda());这样一个函数,那么它显然会参与重载决策,而::ns::f又被特化出来了,那必然会导致重载失败。

现在问题就成了“当我通过使用的方式特化某个函数时,编译器有没有权力自行特化其他函数”,貌似这个权力是有的(吧?)

这里的问题在于,首先lambda是函数对象,其次这个对象声明在main()作用域,然后就算using了::ns::f,f仍然在作用域,如果曾经特化过f的某个版本,而根据ADT肯定能找到::f(::f是main()的上层),那么重载失败就是可能的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

SACC2019中国系统架构师大会

【数字转型 架构演进】SACC2019中国系统架构师大会,7折限时优惠重磅来袭!
2019年10月31日~11月2日第11届中国系统架构师大会(SACC2019)将在北京隆重召开。四大主线并行的演讲模式,1个主会场、20个技术专场、超千人参与的会议规模,100+来自互联网、金融、制造业、电商等领域的嘉宾阵容,将为广大参会者提供一场最具价值的技术交流盛会。

限时七折期:2019年8月31日前


----------------------------------------

大会官网>>
  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP