【C++ 拾遗】C++'s most vexing parse
C++'s most vexing parse 是 Scott Meyers 在其名著《Effective STL》中创造的一个术语。
Scott 用这个术语来形容 C++ 标准对于 declaration 语句的消歧义(ambiguity resolution)约定与常人的认知相悖。
形如 Type() 或 Type(name) 的表达在某些情况下具有歧义(syntax ambiguity)。
一
T1 name(T2());
这是一个 declaration statement。
既可视作声明了一个类型为 T1 名为 name 的 object,并且用一个类型为 T2 的 object 作为其 initilizer(即标准中所谓「an object declaration with a function-style cast as the initializer」),也可视作声明了一个返回值类型为 T1 名为 name 的函数,此函数有一个参数,参数类型为「指向返回值类型为 T2,参数为空的函数的指针」。
C++ 标准规定把这样的 statement 视作函数声明。
二
T1 name1(T2(name2));
根据 C++ 标准,此时不把 T2(name2) 视为「a function style cast」,而将其视为 T2 name2,这样整个语句就变成
T1 name1(T2 name2);,显然这是个函数声明。
类似地,
T1 name1(T2(name2), T3(name3)); 被视作 T1 name1(T2 name2, T3 name3);
C++ 标准将上述两种情况总结为
..., the choice is between a function declaration with a redundant set of parentheses around a parameter name and an object declaration with a function-style cast as the initializer. ..., the resolution is to consider any construct that could possibly be a declaration a declaration... A declaration can be explicitly disambiguated by adding parentheses around the argument. The ambiguity can be avoided by use of copy-initialization or list-initialization syntax, or by use of a non-function-style cast.
并给出了例子
struct S {
S(int);
};
void foo(double a) {
S w(int(a)); // function declaration
S x(int()); // function declaration
S y((int(a))); // object declaration
S y((int)a); // object declaration
S z = int(a); // object declaration
}
不难看出,the most vexing parse 的根源在于default constructor、converting constructor 和 conversion operator。
converting constructor 是指调用时只需一个实参的 constructor。From C++ Primer (5th edition):
Every constructor that can be called with a single argument defines an implicit conversion to a class type. Such constructors are sometimes referred to as converting constructors.
C++ Primer 上关于 conversion operator 的内容
A conversion operator is a special kind of member function that converts a value of a class type to a value of some other type. A conversion function typically has the general form
operator T() const;
where T represents a type.
Conversion operators have no explicitly stated return type and no parameters, and they must be defined as member functions. Conversion operations ordinarily should not change the object they are converting. As a result, conversion operators usually should be defined as const members.
More to read
The Most Vexing Parse: How to Spot It and Fix It Quickly
【C++ 拾遗】C++'s most vexing parse的更多相关文章
- Effective STL 笔记: Item 6--Be alert for C++'s most vexing parse
假设有个文件里面记录的一系列的 int 值,现在我们想把这些数值存到一个 List 里面,结合 Item 5, 我们可能会写出下面的代码: ifstream dataFile("ints.d ...
- C++ 11 多线程--线程管理
说到多线程编程,那么就不得不提并行和并发,多线程是实现并发(并行)的一种手段.并行是指两个或多个独立的操作同时进行.注意这里是同时进行,区别于并发,在一个时间段内执行多个操作.在单核时代,多个线程是并 ...
- (转)C++语言的15个晦涩特性
原文链接: Evan Wallace 翻译: 伯乐在线- 敏敏 译文链接: http://blog.jobbole.com/54140/ 这个列表收集了 C++ 语言的一些晦涩(Obscure)特 ...
- C++你不知道的那些事儿—C++语言的15个晦涩特性
这个列表收集了 C++ 语言的一些晦涩(Obscure)特性,是我经年累月研究这门语言的各个方面收集起来的.C++非常庞大,我总是能学到一些新知识.即使你对C++已了如指掌,也希望你能从列表中学到一些 ...
- [译]GotW #1: Variable Initialization 续
Answer 2. 下面每行代码都做了什么? 在Q2中,我们创建了一个vector<int>且传了参数10和20到构造函数中,第一种情况下(10,20),第二种情况是{10, 20}. 它 ...
- [译]GotW #1: Variable Initialization
原文地址:http://herbsutter.com/2013/05/09/gotw-1-solution/ 第一个问题强调的是要明白自己在写什么的重要性.下面有几行简单的代码--它们大多数之间都有区 ...
- [Effective Modern C++] Item 7. Distinguish between () and {} when creating objects - 辨别使用()与{}创建对象的差别
条款7 辨别使用()与{}创建对象的差别 基础知识 目前已知有如下的初始化方式: ); ; }; }; // the same as above 在以“=”初始化的过程中没有调用赋值运算,如下例所示: ...
- c++ 多线程 0
1.1 何谓并发 最简单和最基本的并发,是指两个或更多独立的活动同时发生. (注意区别于计算机中的并发情况!!!!!!!!!!见下面) 1.1.1 计算机系统中的并发:是指在单个系统里同时执行多个独 ...
- C++学习书籍推荐《Effective STL(英文)》下载
百度云及其他网盘下载地址:点我 作者简介 Scott Meyers is one of the world's foremost authorities on C++, providing train ...
随机推荐
- java对一个int数组进行排序、去重
思路: 1.使用 HashSet 进行去重 2.将 HashSet 变为 TreeSet 3.使用 TreeSet 进行排序 4.将 Set 变为 Integer 数组 5.将 Integer 数组变 ...
- Oracle多表连接方法
笛卡尔连接[结果集为各表记录的乘积] SELECTt * FROM table_1, table_2, table_n SELECTt * FROM table_1 CROSS JOIN table_ ...
- 10^9以上素数判定,Miller_Rabin算法
#include<iostream> #include<cstdio> #include<ctime> #include<string.h> #incl ...
- 【MYSQL笔记2】复制表,在已有表的基础上设置主键,insert和replace
之前我自己建立好了一个数据库xscj:表xs是已经定义好的 具体的定义数据类型如下: 为了复制表xs,我们新建一个表名为xstext,使用下列语句进行复制xs,或者说是备份都可以: create ta ...
- 介绍hadoop中的hadoop和hdfs命令
有些hive安装文档提到了hdfs dfs -mkdir ,也就是说hdfs也是可以用的,但在2.8.0中已经不那么处理了,之所以还可以使用,是为了向下兼容. 本文简要介绍一下有关的命令,以便对had ...
- intellij中导入java包
- 4W条人才表循环处理业务sql优化过程
场景: 使用windows服务定时更新合同数据:执行存储过程(pas_RefreshContractStatus),但存储过程里面有一个需要更新4W条人才表循环处理业务 问题: 循环更新4W条人才表状 ...
- PHP获取异常信息
try { } catch (\Exception $e) { $extra = [ 'code' => $e->getCode(), 'msg' => $e->getMess ...
- Lo、Hi、HiByte、LoWord、HiWord、MakeWord、MakeLong、Int64Rec
本话题会涉及到: Lo.Hi.HiByte.LoWord.HiWord.MakeWord.MakeLong.Int64Rec 譬如有一个 Cardinal 类型的整数: 1144201745其十六进制 ...
- linux学习(1)——这是一个新的开始,加油吧少年
(一)自己简单总结 学会使用简单命令 Tab:实现自动补全功能 Ctrl+D:退出当前终端 Ctrl+Z:暂停当前进程 Ctrl+L:清屏 Ctrl+A:可以让光标移动到最前列 Ctrl+E:可以让 ...