C++ Most vexing parse(C++最头疼的解析)
首先需要了解,在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++最头疼的解析)相关推荐
- C++‘s most vexing parse
C++'s most vexing parse 直接看一个例子: #include<iostream> #include<thread> #include <chrono ...
- R:parse函数和eval函数解析字符串为命令并运行
文章目录 例子1 例子2 例子3:回归函数lm中 例子4:绘图函数ggplot中 parse函数解析字符串为表达式:eval函数执行表达式输出结果:parse函数和eval函数在自定义函数中常常非常有 ...
- 我关注的一周技术动态 2015.11.08
分布式系统实践 1. 为什么大部分NoSQL不提供分布式事务? http://www.jdon.com/47671?hmsr=toutiao.io&utm_medium=toutiao.io& ...
- JSONObject JSONArray各种用法以及js eval()函数与JSON.parse的区
2019独角兽企业重金招聘Python工程师标准>>> 一.在后台使用JSONObject对象,并将从数据库中取出来的数据直接使用 JSONObject的put方法放进去,再将这个J ...
- JSON.parse()和eval()的区别
json格式非常受欢迎,而解析json的方式通常用JSON.parse()但是eval()方法也可以解析,这两者之间有什么区别呢? JSON.parse()之可以解析json格式的数据,并且会对要解析 ...
- JSON.parse与eval的区别
JSON.parse与eval和能将一个字符串解析成一个JSON对象,但还是有挺大区别. 测试代码 var A = "{ a: 1 , b : 'hello' }"; var B ...
- php json.parse,JSON.parse()与JSON.stringify()和eval()使用方法详解
这次给大家带来JSON.parse()与JSON.stringify()和eval()使用方法详解,JSON.parse()与JSON.stringify()和eval()使用的注意事项有哪些,下面就 ...
- java的parse方法_Java即时类| parse()方法与示例
java的parse方法 即时类parse()方法 (Instant Class parse() method) parse() method is available in java.time pa ...
- angular1.x 中重要指令介绍($eval,$parse和$compile)
这篇文章是我两年前在博客园写的,现在移植过来,不过Angular 1.x 在国内用的人已经不多了,希望能帮助到有需要的人 在 angular 的服务中,有一些服务你不得不去了解,因为他可以说是 ng ...
最新文章
- Java数据结构与算法(25) - ch11哈希(双重哈希)
- 零基础学Python(第三章 基础语法)
- 在ASP.NET Core中使用EPPlus导入出Excel文件
- 2019-ACM-ICPC-南京区网络赛-E. K Sum(莫比乌斯反演 + 杜教筛)
- 机器码合集开源易语言源码-市场上带多数的
- 51单片机计算器_基于51单片机的倒计时温度检测报警器
- php.ini添加的变量读取,PHP5 在扩展里使用 INI 指令(直接添加和配合全局变量两种方式)...
- ArcGIS制图表达Representation-规则和几何效果
- 1.Linux 高性能服务器编程 --- TCP/IP 协议族
- 发点牢骚,关于微软,关于WPF/E
- python网络请求_Python HTTP请求
- fastboot工具的操作流程
- Spring学习笔记(三十六)——SpringBoot 实现大文件分片上传、断点续传及秒传
- 还挺好看!用命令行画思维导图;66天机器学习之旅;斯坦福CS234 强化学习课程;哈佛CS50 计算机科学导论课程;前沿论文 | ShowMeAI资讯日报
- 怎样往阿里云windows服务器传文件
- 投资组合分析的 GE McKinsey 矩阵
- 关于调制比、过调制、基波电压和母线电压的概念和关系总结
- 关于本号,你想看的都在这里
- 计算机等级考试考几级才能成为数据库工程师?
- 微信App支付源码坑注释