「C++」C++中最令人头痛的语法解析是什么?

毫无疑问,C++是一个很复杂的语言,C++中有一个很经典的术语叫:

最令人头痛的语法解析

「C++」C++中最令人头痛的语法解析是什么?


定义

最令人头痛的语法解析是C++编程语言中句法歧义消解的一种特殊形式。大神Scott Meyers在有效的STL(2001)中使用了这个术语。(1)它在C++语言标准的第8.2节中被正式定义。

看下面的代码:

<code>class Timer {
 public:
  Timer();
};

class TimeKeeper {
 public:
  TimeKeeper(const Timer& t);

  int get_time();
};

int main() {
  TimeKeeper time_keeper(Timer());
  return time_keeper.get_time();
}/<code>

随后我们在写出下面的代码:

<code> TimeKeeper time_keeper(Timer());/<code>

这段代码似乎有歧义,因为它可以被解释为

  • 定义并初始化一个叫time_keeper的类。
  • 函数申明,声明一个叫time_keeper的函数,返回值类型为TimeKeeper.

大多数程序员期望第一个,但是C++标准要求它被解释为第二个。

例如,g++给出以下错误消息:

<code>time_keeper.cc: In function ‘int main()’:
time_keeper.cc:15: error: request for member ‘get_time’ in ‘time_keeper’, which is
  of non-class type ‘TimeKeeper(Timer (*)())’/<code>

上面错误的意思是,我们不应该这么调用get_time函数,因为编译器把它当成了一个函数声明,没有成员变量,我们在main函数中这么调用就会报错。


clang中会发出这样的警告:

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


解决办法

  • 多用一个括号
    TimeKeeper time_keeper((Timer()));
  • 使用拷贝初始化
    TimeKeeper time_keeper = TimeKeeper(Timer());
  • C++11以后,可以使用uniform initialization
    TimeKeeper time_keeper{Timer()};
    TimeKeeper time_keeper(Timer{});
    TimeKeeper time_keeper{Timer{}}
    ;

  • 分享到:


    相關文章: