首先需要了解,在C++中,如下三种方式声明了同一个函数:

int f(double d); //声明接受一个double参数d,返回值为int类型的函数
int f(double (d));//效果一样,参数名外的括号会被忽略
int f(double);//直接省略参数名 

同样地,如下三种方法也声明了同一个函数:

int g(double (*pf)()); //声明返回值为int类型的函数,接受一个返回类型为double无参数的函数指针pf
int g(double pf());//效果一样,pf是隐式函数指针
int g(double ());//直接省略参数名 

对于如下示例:

#include <iostream>class Timer
{
public:Timer();
};class TimeKeeper
{
public:TimeKeeper(const Timer& t);int get_time() const;
};int main()
{TimeKeeper time_keeper(Timer());return time_keeper.get_time();
}

这段代码编译通不过,在visual studio上报错:

error: request for member 'get_time' in 'time_keeper', which is of non-class type 'TimeKeeper(Timer (*)())'return time_keeper.get_time();

问题出在

 TimeKeeper time_keeper(Timer());

该行可以有两种解读:

1. 定义了一个类型为TimeKeeper的对象time_keeper,用一个匿名的类型为Timer的实例初始化。

2. 声明了一个返回类型为TimeKeeper,函数名为time_keeper,有一个匿名参数,参数类型为指向返回类型为Timer,参数为空的函数指针。

绝大部分程序员期望是第一种情况,但是C++标准把这样的声明视为第二种,既函数声明。

解释如下:

T1 name1(T2(name2));

根据 C++ 标准,此时不把 T2(name2) 视为「a function style cast」,而将其视为 T2 name2,这样整个语句就变成
T1 name1(T2 name2);,显然这是个返回类型为T1,参数类型为T2的函数声明。

类似地,
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 declarationS x(int());                   // function declarationS y((int(a)));                // object declarationS y((int)a);                  // object declarationS z = int(a);                 // object declaration
}

不难看出,the most vexing parse 的根源在于default constructor、converting constructor 和 conversion operator。

converting constructor 是指调用时只需一个实参(或者多个参数但是只有第一个参数没有默认值)的 constructor。

conversion operator把类类型转换为T类型,如:operator T() const;

解决方法

1. 添加额外的一对括号, TimeKeeper time_keeper((Timer()));

2. 使用复制初始化, TimeKeeper time_keeper = TimeKeeper(Timer());

3. 从C++11起,使用统一的初始化:

a. TimeKeeper time_keeper{Timer()};

b. TimeKeeper time_keeper(Timer{});

c. TimeKeeper time_keeper{Timer{}};

C++ Most vexing parse(C++最头疼的解析)相关推荐

  1. C++‘s most vexing parse

    C++'s most vexing parse 直接看一个例子: #include<iostream> #include<thread> #include <chrono ...

  2. R:parse函数和eval函数解析字符串为命令并运行

    文章目录 例子1 例子2 例子3:回归函数lm中 例子4:绘图函数ggplot中 parse函数解析字符串为表达式:eval函数执行表达式输出结果:parse函数和eval函数在自定义函数中常常非常有 ...

  3. 我关注的一周技术动态 2015.11.08

    分布式系统实践 1. 为什么大部分NoSQL不提供分布式事务? http://www.jdon.com/47671?hmsr=toutiao.io&utm_medium=toutiao.io& ...

  4. JSONObject JSONArray各种用法以及js eval()函数与JSON.parse的区

    2019独角兽企业重金招聘Python工程师标准>>> 一.在后台使用JSONObject对象,并将从数据库中取出来的数据直接使用 JSONObject的put方法放进去,再将这个J ...

  5. JSON.parse()和eval()的区别

    json格式非常受欢迎,而解析json的方式通常用JSON.parse()但是eval()方法也可以解析,这两者之间有什么区别呢? JSON.parse()之可以解析json格式的数据,并且会对要解析 ...

  6. JSON.parse与eval的区别

    JSON.parse与eval和能将一个字符串解析成一个JSON对象,但还是有挺大区别. 测试代码 var A = "{ a: 1 , b : 'hello' }"; var B ...

  7. php json.parse,JSON.parse()与JSON.stringify()和eval()使用方法详解

    这次给大家带来JSON.parse()与JSON.stringify()和eval()使用方法详解,JSON.parse()与JSON.stringify()和eval()使用的注意事项有哪些,下面就 ...

  8. java的parse方法_Java即时类| parse()方法与示例

    java的parse方法 即时类parse()方法 (Instant Class parse() method) parse() method is available in java.time pa ...

  9. angular1.x 中重要指令介绍($eval,$parse和$compile)

    这篇文章是我两年前在博客园写的,现在移植过来,不过Angular 1.x 在国内用的人已经不多了,希望能帮助到有需要的人 在 angular 的服务中,有一些服务你不得不去了解,因为他可以说是 ng ...

最新文章

  1. Java数据结构与算法(25) - ch11哈希(双重哈希)
  2. 零基础学Python(第三章 基础语法)
  3. 在ASP.NET Core中使用EPPlus导入出Excel文件
  4. 2019-ACM-ICPC-南京区网络赛-E. K Sum(莫比乌斯反演 + 杜教筛)
  5. 机器码合集开源易语言源码-市场上带多数的
  6. 51单片机计算器_基于51单片机的倒计时温度检测报警器
  7. php.ini添加的变量读取,PHP5 在扩展里使用 INI 指令(直接添加和配合全局变量两种方式)...
  8. ArcGIS制图表达Representation-规则和几何效果
  9. 1.Linux 高性能服务器编程 --- TCP/IP 协议族
  10. 发点牢骚,关于微软,关于WPF/E
  11. python网络请求_Python HTTP请求
  12. fastboot工具的操作流程
  13. Spring学习笔记(三十六)——SpringBoot 实现大文件分片上传、断点续传及秒传
  14. 还挺好看!用命令行画思维导图;66天机器学习之旅;斯坦福CS234 强化学习课程;哈佛CS50 计算机科学导论课程;前沿论文 | ShowMeAI资讯日报
  15. 怎样往阿里云windows服务器传文件
  16. 投资组合分析的 GE McKinsey 矩阵
  17. 关于调制比、过调制、基波电压和母线电压的概念和关系总结
  18. 关于本号,你想看的都在这里
  19. 计算机等级考试考几级才能成为数据库工程师?
  20. 微信App支付源码坑注释

热门文章

  1. Python实验一:创建数组并进行运算、创建一个国际象棋棋盘
  2. 为什么闹钟设置了却不响_手机闹钟不响是怎么回事
  3. 20190220《前赤壁赋---苏轼》
  4. 中鑫吉鼎|家庭理财规划具体有哪些步骤
  5. ElasticSearch Aggregations使用总结详解
  6. 如何裁剪动图像素?gif裁剪尺寸的方法
  7. php 加入即时推送功能
  8. 内蒙古工业大学c语言设计考试卷,求助:大一c语言考试题型是啥啊?后天就考了。...
  9. 为什么说HTC U11选择百度DuerOS是最聪明的做法
  10. GIT底层命令之git cat-file