最令人烦恼的解析最令人烦恼的解析 (most vexing parse)是C++编程语言中的一种反直觉的二义性解析形式。 在一些场景下,编译器无法区分某语句是初始化时某对象的参数,还是声明一个函数时指定参数类型。在这些情况下,编译器将该行解释为函数声明。 出现术语"most vexing parse" 最初由Scott Meyers用于2001年的书籍 Effective STL中。[1] 尽管在C语言中不常见,但这种现象在 C++ 中很常见,直到C++11推出了统一初始化才得以解决。[2] 示例C风格强制类型转换一个例子如下: void f(double my_dbl) {
int i(int(my_dbl));
}
上面的第 2 行是有歧义的。一种可能的解释是声明一个变量 // 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());
是有歧义的,它可以被解释为:
C ++标准采取第二种解释,这与上面的第9行不一致。例如,Clang++警告第9行存在最令人烦恼的解析,并报错:[3] $ 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(); ~~~~~~~~~~~^~~~~~~~~ 解决方案这些有歧义的声明往往不会被解析为程序员所期望的语句。[4][5] 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 起)是统一(大括号)初始化。[6] 这也允许完全省略类型名称: //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 之前,强制获得预期解释的常用手段是使用额外的括号或拷贝初始化:[5] TimeKeeper time_keeper( /*Avoid MVP*/ (Timer()) );
TimeKeeper time_keeper = TimeKeeper(Timer());
后一种写法中,拷贝赋值运算符 有可能被编译器优化。[7] 自C++17开始,这种优化受到保证。[8] 注记
参考资料
外部链接
|
Index:
pl ar de en es fr it arz nl ja pt ceb sv uk vi war zh ru af ast az bg zh-min-nan bn be ca cs cy da et el eo eu fa gl ko hi hr id he ka la lv lt hu mk ms min no nn ce uz kk ro simple sk sl sr sh fi ta tt th tg azb tr ur zh-yue hy my ace als am an hyw ban bjn map-bms ba be-tarask bcl bpy bar bs br cv nv eml hif fo fy ga gd gu hak ha hsb io ig ilo ia ie os is jv kn ht ku ckb ky mrj lb lij li lmo mai mg ml zh-classical mr xmf mzn cdo mn nap new ne frr oc mhr or as pa pnb ps pms nds crh qu sa sah sco sq scn si sd szl su sw tl shn te bug vec vo wa wuu yi yo diq bat-smg zu lad kbd ang smn ab roa-rup frp arc gn av ay bh bi bo bxr cbk-zam co za dag ary se pdc dv dsb myv ext fur gv gag inh ki glk gan guw xal haw rw kbp pam csb kw km kv koi kg gom ks gcr lo lbe ltg lez nia ln jbo lg mt mi tw mwl mdf mnw nqo fj nah na nds-nl nrm nov om pi pag pap pfl pcd krc kaa ksh rm rue sm sat sc trv stq nso sn cu so srn kab roa-tara tet tpi to chr tum tk tyv udm ug vep fiu-vro vls wo xh zea ty ak bm ch ny ee ff got iu ik kl mad cr pih ami pwn pnt dz rmy rn sg st tn ss ti din chy ts kcg ve
Portal di Ensiklopedia Dunia