首页 > 编程语言 >C++'s most vexing parse

C++'s most vexing parse

时间:2022-11-10 14:12:33浏览次数:63  
标签:TimeKeeper int vexing Timer parse most C++ time keeper

本文地址 https://www.cnblogs.com/wanger-sjtu/p/16876846.html

C++'s most vexing parse 是 Scott Meyers 在其名著《Effective STL》中创造的一个术语。Scott 用这个术语来形容 C++ 标准对于 declaration 语句的消歧义(ambiguity resolution)约定与常人的认知相悖。

最令人烦恼的解析 (most vexing parse)是C++中的一种反直觉的二义性解析形式。 在一些场景下,编译器无法区分某语句是初始化时某对象的参数,还是声明一个函数时指定参数类型。在这些情况下,编译器将该行解释为函数声明。

形如 Type() 或 Type(name) 的表达在某些情况下具有歧义(syntax ambiguity)。

C风格强制类型转换

void f(double my_dbl) {
  int i(int(my_dbl));
}

上面的第 2 行是有歧义的。一种可能的解释是声明一个变量i,初始值通过转换my_dbl 到一个int而来。但是,C 允许在函数参数声明周围使用多余的括号;因此,声明的i实际上等同于以下代码:

// A function named i takes an integer and returns an integer.
int i(int my_dbl);

未命名的临时对象

struct Timer {};
struct TimeKeeper {
  explicit TimeKeeper(Timer t);
  int get_time();
};

int main() {
  TimeKeeper time_keeper(Timer());
  return time_keeper.get_time();
}

其中

TimeKeeper time_keeper(Timer());

是有歧义的,它可以被解释为:

  1. 一个变量:定义为类TimeKeeper的变量time_keeper,用类Timer的匿名实例初始化。
  2. 一个函数声明:声明了一个函数time_keeper,返回一个TimeKeeper,有一个(未命名的)参数。参数的类型是一个(指向)不接受输入并返回Timer对象的函数(的指针)。

[C ++标准]采取第二种解释,这与上面的第9行不一致。例如,Clang++警告第9行存在最令人烦恼的解析,并报错:

$ clang++ time_keeper.cc
**timekeeper.cc:9:25: warning: parentheses were disambiguated as a function declaration**
      **[-Wvexing-parse]**
  TimeKeeper time_keeper(Timer());
                        **^~~~~~~~~**
**timekeeper.cc:9:26: note:** add a pair of parentheses to declare a variable
  TimeKeeper time_keeper(Timer());
                         ^
                         (      )
**timekeeper.cc:10:21: error: member reference base type 'TimeKeeper (Timer (*)())' is not a**
      **structure or union**
  return time_keeper.get_time();
         **~~~~~~~~~~~^~~~~~~~~**

解决方案

这些有歧义的声明往往不会被解析为程序员所期望的语句。C++ 中的函数类型通常隐藏在typedef之后,并且通常具有显式引用或指针限定符。要强制扭转解析的结果,常见做法是换一种不同的对象创建或转换语法

在类型转换的示例中,有两种替代语法:“C 风格强制类型转换”

// declares a variable of type int
int i((int)my_dbl);

或一个static_cast转换:

int i(static_cast<int>(my_dbl));

在变量声明的示例中,首选方法(自 C++11 起)是统一(大括号)初始化。 这也允许完全省略类型名称:

//Any of the following work:
TimeKeeper time_keeper(Timer{});
TimeKeeper time_keeper{Timer()};
TimeKeeper time_keeper{Timer{}};
TimeKeeper time_keeper(     {});
TimeKeeper time_keeper{     {}};

在 C++11 之前,强制获得预期解释的常用手段是使用额外的括号或拷贝初始化:

TimeKeeper time_keeper( /*Avoid MVP*/ (Timer())); // 增加一个括号
TimeKeeper time_keeper = TimeKeeper(Timer());  // c++ 17 拷贝运算可以被优化

标签:TimeKeeper,int,vexing,Timer,parse,most,C++,time,keeper
From: https://www.cnblogs.com/wanger-sjtu/p/16876846.html

相关文章

  • argarse.ArgumentParser.parse_known_args()解析
    大致意思就是:有时间一个脚本只需要解析所有命令行参数中的一小部分,剩下的命令行参数给两一个脚本或者程序。在这种情况下,parse_known_args()就很有用。它很像parse_args(),但......
  • Python下使用argparse模块的脚本参数配置
    python的一个用于命令行参数解析的模块,其专业解释已经有很多了,可以去详查,不做赘述,仅谈谈自己的一些理解。为什么要用argparse模块来为代码导入参数或者文件路径呢?如果是一......
  • HDU 5876 Sparse Graph
    ProblemDescriptioncomplement ofagraph G isagraph H onthesameverticessuchthattwodistinctverticesof H areadjacentifand......
  • ZOJ 2132 the most frequent number
    DescriptionSeven(actuallysix)problemsmaybesomewhatfewforacontest.ButIamreallyunabletodeviseanotherproblemrelatedtoFantasyGameSeries.......
  • webpack中配置CSS兼容性时报错 Failed to parse package.json data
      是因为在package.json中添加了注释正确webpack配置CSS兼容性的步骤:npmipostcss-loaderpostcss-preset-env-D/webpack.config.jsmodule:{    ru......
  • [LeetCode] 1678. Goal Parser Interpretation
    Youowna GoalParser thatcaninterpretastring command.The command consistsofanalphabetof "G", "()" and/or "(al)" insomeorder.TheGoalPar......
  • 【模板】ST 表 Sparse Table
    postedon2022-07-2219:15:58|under模板|sourcetemplate<intN,classT=int,intlogN=20>structSTable{ inttot,lg[N+10];Tf[logN+1][N+10]; STable():tot(0......
  • JS中JSON.parse()方法解析失败的问题
    今天在安卓开发(安卓内嵌cordova,页面采用js+html编写)的过程中,出现了一个问题:      result=JSON.parse(result); 该方法抛出异常:JSON解析失败。在对......
  • python之configparser解析ini文件
    login.ini文件内容如下[data1]username=zhangpassword=123456address=sichuan[data2]username=lipassword=654321address=guangdong通过configparser解析importconfigparse......
  • 50、实例分割SparseInst模型部署mnn、ncnn、rknn,完成业务需求
    基本思想:看了金东大佬的知乎,羡慕其检测速度和效果,业务存在对实例分割的需求,需要移植嵌入式开发板上,趁国庆节休息几天,搞一下几个例子,部署一下 一、下载官方代码,测试一下 首......