C++‘s most vexing parse
C++'s most vexing parse
直接看一个例子:
#include<iostream>
#include<thread>
#include <chrono>using namespace std::chrono_literals;class task {public:void operator() () {std::cout << "task begin..." << std::endl;std::this_thread::sleep_for(2s);std::cout << "task done!" << std::endl;}
};int main() {std::thread t(task());t.join();return 0;
}
这段代码很简单,在主线程(main函数)中起动一个子线程,并等待子线程执行完成。然而,上面代码编译会报错:
test.cpp: In function ‘int main()’:
test.cpp:18:7: error: request for member ‘join’ in ‘t’, which is of non-class type ‘std::thread(task (*)())’18 | t.join();| ^~~~
因为 t
根本就不是一个类类型的对象,而是一个函数,这里的 std::thread t(task())
并非创建一个 std::thread
对象并启动该线程执行,而是申明了一个函数,该函数的返回值类型为 std::thread
,函数名为 t
,参数为一个函数指针(返回值类型为 task,无函数名,参数为空)。这就是本文的主题:C++'s most vexing parse(C++最令人费解的解析)。Scott Meyers 在《Effective STL》中的 Item 6 有相关介绍。
在 C++ 中,加入我们要申明一个函数 f
,返回值类型为 int
,参数类型为 double
,则以下 3 种都是合法的申明方式:
int f(double d);
int f(double (d));
int f(double);
第二个申明,对行参加上圆括号,编译器会认为是冗余的并忽略。第三个省略了行参名。
如果我们想申明一个函数,并且其参数是一个函数指针,下面 3 种写法都是合法的:
int g(double (*pf)());
int g(double pf());
int g(double ());
第二个申明中行参省去指针类型也是合法的,第三个申明中行参直接省去了函数名也是合法的。
更普遍地,对于下面的语句:
T1 name(T2());
T1 name1(T2(name2));
C++都会将其视为函数申明:
- 对于第一个语句,C++将其视为:返回值类型为
T1
名为name
的函数(参数类型为指向返回值类型为T2
,参数为空的函数的指针)。 - 对于第二个语句,C++将其视为:
T1 name1(T2 name2);
显然也是一个函数申明。
再看本文开头给出的例子,就不难理解编译报错的原因了。解决办法也比较多,比如:
std::thread t((task()));std::thread t{task()};task f
std::thread t(f);
至此,本文结束,希望对你有所帮助。
参考:
- Scott Meyers 《Effective STL》
- http://eel.is/c++draft/dcl.ambig.res
- https://www.fluentcpp.com/2018/01/30/most-vexing-parse/
C++‘s most vexing parse相关推荐
- C++ Most vexing parse(C++最头疼的解析)
首先需要了解,在C++中,如下三种方式声明了同一个函数: int f(double d): //声明接受一个double参数d,返回值为int类型的函数 int f(double (d))://效果一 ...
- 将整个ASCII文件读入C ++ std :: string [重复]
本文翻译自:Read whole ASCII file into C++ std::string [duplicate] This question already has an answer her ...
- [转]C++ 11 多线程--线程管理
转载地址:https://www.cnblogs.com/wangguchangqing/p/6134635.html 说到多线程编程,那么就不得不提并行和并发,多线程是实现并发(并行)的一种手段.并 ...
- C/C++ 中生成特定范围内的随机数
大家在写 C/C++ 程序时,难免会遇到要求获取某个范围内的随机数,我查阅了一些资料后,总结如下.本文分两部分,先介绍 C 语言中与随机数相关的两个函数 srand 和 rand,后介绍 C++ 中的 ...
- C++ 11 多线程--线程管理
说到多线程编程,那么就不得不提并行和并发,多线程是实现并发(并行)的一种手段.并行是指两个或多个独立的操作同时进行.注意这里是同时进行,区别于并发,在一个时间段内执行多个操作.在单核时代,多个线程是并 ...
- C++你不知道的那些事儿—C++语言的15个晦涩特性
这个列表收集了 C++ 语言的一些晦涩(Obscure)特性,是我经年累月研究这门语言的各个方面收集起来的.C++非常庞大,我总是能学到一些新知识.即使你对C++已了如指掌,也希望你能从列表中学到一些 ...
- 面经——C/C++常见面试知识点总结附面试真题
参考:C/C++ 面试题 作者:zhaouc 发布时间: 2015-02-15 15:51:00 网址:https://blog.csdn.net/zhaouc/article/details/438 ...
- C++11多线程----线程管理
说到多线程编程,那么就不得不提并行和并发,多线程是实现并发(并行)的一种手段.并行是指两个或多个独立的操作同时进行.注意这里是同时进行,区别于并发,在一个时间段内执行多个操作.在单核时代,多个线程是并 ...
- 大括号之谜:C++的列表初始化语法解析
转载: https://segmentfault.com/a/1190000039362151 摘要:有朋友在使用std::array时发现一个奇怪的问题:当元素类型是复合类型时,编译通不过. 有朋友 ...
最新文章
- CocosCreator TOUCH_MOVE事件
- Java虚拟机2:Java 运行时数据区
- rtsp协议_如何在RTSP协议视频智能平台EasyNVR未登录的情况下调用通道直播的接口?...
- Play on Words UVA - 10129 (有向图欧拉路径)
- USB device如何进入suspend模式
- 再谈迭代器,生成器,yield,及和类的使用
- 流媒体技术的应用与发展前景
- UI设计素材|app表单模板,临摹学习,有效提高设计水平!
- 默认栅格大小为多少_用于创建空栅格的ST_MakeEmptyRaster函数
- Liststring绑定到DataGridView控件
- JTT808、JTT809、JTT796、JTT794、JTT1077、JTT1078区别与交通部道路运输车辆卫星定位系统部标标准大全下载地址...
- 正则表达式网站在线测试
- 讲解c程序设计语言的比喻,《C语言程序设计》论文关于比喻在《C语言程序设计》课程教学中的应用论文范文参考资料...
- 纽约峭石之巅观景台:从直入云天的城市之巅眺望纽约全景
- mybatis lazyload
- SAP MM 物料主数据-物料版次-基础应用
- ES20-JAVA API 词项搜索
- stm32--数码管
- 还记得,你发送的第一封电子邮件是什么时候吗?
- 博弈论-斐波那契博弈
热门文章
- Pr剪切的视频在优酷上播放为绿屏的解决方案
- input在iphone下显示上边框解决方案
- 基于微信小程序带后端ssm接口小区物业管理平台设计
- sed与awk笔记分享
- buaacoding ?.海洋与陆地
- JAVA+MYSQL+CSV用正则表达式获取CPU天梯分数
- MFC 实现检测ppt是否正在播放
- 在react中使用fetch
- 基于javaweb+jsp的茶叶售卖商城系统(java+SSM+JSP+EasyUi+mysql)
- (免费分享)基于springboot健康运动-带论文