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的更多相关文章

  1. Effective STL 笔记: Item 6--Be alert for C++'s most vexing parse

    假设有个文件里面记录的一系列的 int 值,现在我们想把这些数值存到一个 List 里面,结合 Item 5, 我们可能会写出下面的代码: ifstream dataFile("ints.d ...

  2. C++ 11 多线程--线程管理

    说到多线程编程,那么就不得不提并行和并发,多线程是实现并发(并行)的一种手段.并行是指两个或多个独立的操作同时进行.注意这里是同时进行,区别于并发,在一个时间段内执行多个操作.在单核时代,多个线程是并 ...

  3. (转)C++语言的15个晦涩特性

    原文链接: Evan Wallace   翻译: 伯乐在线- 敏敏 译文链接: http://blog.jobbole.com/54140/ 这个列表收集了 C++ 语言的一些晦涩(Obscure)特 ...

  4. C++你不知道的那些事儿—C++语言的15个晦涩特性

    这个列表收集了 C++ 语言的一些晦涩(Obscure)特性,是我经年累月研究这门语言的各个方面收集起来的.C++非常庞大,我总是能学到一些新知识.即使你对C++已了如指掌,也希望你能从列表中学到一些 ...

  5. [译]GotW #1: Variable Initialization 续

    Answer 2. 下面每行代码都做了什么? 在Q2中,我们创建了一个vector<int>且传了参数10和20到构造函数中,第一种情况下(10,20),第二种情况是{10, 20}. 它 ...

  6. [译]GotW #1: Variable Initialization

    原文地址:http://herbsutter.com/2013/05/09/gotw-1-solution/ 第一个问题强调的是要明白自己在写什么的重要性.下面有几行简单的代码--它们大多数之间都有区 ...

  7. [Effective Modern C++] Item 7. Distinguish between () and {} when creating objects - 辨别使用()与{}创建对象的差别

    条款7 辨别使用()与{}创建对象的差别 基础知识 目前已知有如下的初始化方式: ); ; }; }; // the same as above 在以“=”初始化的过程中没有调用赋值运算,如下例所示: ...

  8. c++ 多线程 0

    1.1 何谓并发 最简单和最基本的并发,是指两个或更多独立的活动同时发生.  (注意区别于计算机中的并发情况!!!!!!!!!!见下面) 1.1.1 计算机系统中的并发:是指在单个系统里同时执行多个独 ...

  9. C++学习书籍推荐《Effective STL(英文)》下载

    百度云及其他网盘下载地址:点我 作者简介 Scott Meyers is one of the world's foremost authorities on C++, providing train ...

随机推荐

  1. Python——字典

    字典是一种key-value 的 数据类型,使用就想我们上学用的字典.可以通过笔画,字母来查对应页的详细内容. 特性:1. 字典是无须的.(如果光打印字典里的字符串,那么排序不会按照顺序排,因为字典是 ...

  2. java动态返回一个大对象里多个小对象map返回,el表达式用c:set拼接

    基于堆内存,先把map放到返回值里 Map _map=new HashMap(); modelAndView.addObject("pledgeInsurance",_map);/ ...

  3. Python面向对象--高级(二)

    ## 使用__slots__限制类的属性 - 之前说到,可以通过在类外部实例或者类名任意定义实例属性或者类属性或者方法 class Person(object): pass Person.name = ...

  4. CentOS7下安装FTP

    1.安装vsftpd yum install -y vsftpd 2.设置 使用命令systemctl status vsftpd.service查看ftp状态. 开启ftp systemctl st ...

  5. Fruits【水果】

    Fruits Many of us love July because it's the month when nature's berries and stone fruits are in abu ...

  6. 寻找物体的凸包 opencv

    凸包的含义: 在二维平面上给定点集,凸包就是将最外层的点连接起来构成的凸多边形.并且这个凸多边形能包含点集中所有的点.OPENCV中: convexHull函数用于寻找图像点集中的凸包.它有六个输入参 ...

  7. Background Segment CNT

    CNT简介 CNT算法是OpenCV Contrib 模块中的背景减除(Background segment)算法之一.相较于OpenCV提供的其他背景减 除算法,该算法具有运行速度快,检测精度高等优 ...

  8. 分布式爬虫:使用Scrapy抓取数据

    分布式爬虫:使用Scrapy抓取数据 Scrapy是Python开发的一个快速,高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据.Scrapy用途广泛,可以用于数据挖掘. ...

  9. SpringMVC---四大注解

    SpringMVC四大注解 Component 通用标注,在不清楚使用哪个注解的时候,可以使用Component通用注解 Controller 标注web请求控制器 Service 标注Service ...

  10. 3. 与服务器对话:理解 HTTP 协议

    0.服务器与本地交换机制 2.详解HTtp服务 (1)与服务器对话的流程 (2)Reque 请求 (3)Response 响应 200 成功 404 没有网页 (4)Get/Post区别 get查询数 ...