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

出现
--

术语"most vexing parse" 最初由Scott Meyers用于2001年的书籍 *Effective STL*中。 尽管在C语言中不常见，但这种现象在 C++ 中很常见，直到C++11推出了统一初始化才得以解决。

示例
--

### 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开始，这种优化受到保证。

注记
--

1. ↑  根据C++类型退化规则，作为参数声明的函数等价于一个指向同类型函数的指针。参见C++函数对象的实例。

参考资料
----

1. ↑  Meyers, Scott.. Addison-Wesley. 2001. ISBN 0-201-74962-9.
2. ↑  Coffin, Jerry.. Stack Overflow. 29 December 2012  [2021-01-17]. （原始内容存档于2021-11-25）.
3. ↑  Lattner, Chris.. LLVM Project Blog. The Most Vexing Parse. 5 April 2010  [2021-01-17]. （原始内容存档于26 September 2020）.
4. ↑  DrPizza; Prototyped; wb; euzeka; Simpson, Homer J.. ArsTechnica OpenForum. October 2002  [2021-01-17]. （原始内容存档于2021-11-25）.
5. 1 2  Boccara, Jonathan.. Fluent C++. 2018-01-30  [2021-01-17]. （原始内容存档于2021-11-25） （美国英语）.
6. ↑  Stroustrup, Bjarne.. www.stroustrup.com. Uniform initialization syntax and semantics. 19 August 2016  [2021-01-17]. （原始内容存档于2021-08-20） （英语）.
7. ↑ . C++ FAQ. What is copy elision? What is RVO?.  [2021-01-17]. （原始内容存档于2021-11-25）.
8. ↑  Devlieghere, Jonas.. Jonas Devlieghere. 2016-11-21  [2021-01-17]. （原始内容存档于2021-11-25） （英语）.  Note, however, the caveats covered in Brand, C++.. Microsoft C++ Team Blog. 2018-12-11  [2021-01-17]. （原始内容存档于2021-11-25） （美国英语）.

外部链接
----

* Discussion in the C++03 standard final draft (see §8.2 Ambiguity resolution *[dcl.ambig.res]*):
* CppReference on direct initialization (the sort vulnerable to the most vexing parse):  （页面存档备份，存于）