「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{}}
    ;

  • 分享到:


    相關文章: