2015-04-02 65 views
48

以下代碼在我嘗試使用C++ 98,C++ 11和C++ 14模式的所有版本的GCC上產生後續編譯錯誤:錯誤:不合時宜的舊式基類初始化程序

struct T 
{ 
    T(void* x) : (x) {} 
}; 

// main.cpp: In constructor 'T::T(void*)': 
// main.cpp:3:18: error: anachronistic old-style base class initializer [-fpermissive] 
//  T(void* x) : (x) {} 
//     ^
// main.cpp:3:16: error: unnamed initializer for 'T', which has no base classes 
//  T(void* x) : (x) {} 

當然,這顯然是破碎的代碼,因爲我實際上並沒有初始化任何東西。

但爲什麼它是一個基礎級的初始化程序,爲什麼它是「不合時宜的」,而不是簡單的錯誤?曾經有效嗎?什麼時候?這是什麼意思?


only related references我發現這個在網絡上被人穿過的錯誤來當一個成員的名字被意外macro'd出來,有效地產生相同的代碼上面:

#define bar 
//^some library could have done this 

struct T 
{ 
    T(int x) 
     : bar(x) // effectively just `: (x)` 
    {} 

    int bar;  // will cause its own error 
}; 

那些人從來沒有找到錯誤的含義,儘管他們後來至少發現了他們的程序被破壞的原因。

+3

我會_guess_這個語法是在類C中的基類初始化語法,就在最早的[非標準] C++引入多重繼承之前。 – 2015-04-02 21:04:29

+0

這也似乎是對我來說最合理的假設。不幸的是,我一直無法通過常見的渠道找到第一版或第二版的「The C++ Programming Language」。不過,我確定SO上的某個人有一個。 – Brian 2015-04-02 21:09:50

+3

尋找「註釋參考手冊」(ARM)也許? – 2015-04-02 21:10:50

回答

51

的文檔中找到了1984-5發佈CFRONT的,第一個C++編譯器:

The constructor can be written like this:

vec.vec(int lb, int hb) : (hb-lb+1) 
    { 
     if (hb-lb<0) hb * lb 
     low = lb; 
     high = hb; 
    } 

The construct : (hb-lb+1) is used to specify the argument list needed for the base class constructor vector().

有道理,如果你想想看。據推測,基類的顯式命名被添加來支持多重繼承。

歸功於http://www.softwarepreservation.org/projects/c_plus_plus/歸檔文件。

...哇,我剛纔意識到「CFront」是一個文字遊戲。

+3

....好找。 – Columbo 2015-04-02 21:12:46

+0

在我們之間,這是一個完美的平分。 :)「C++ 2.0」在1989年對它進行了改變,以支持多重繼承。 – 2015-04-02 21:21:52

+6

也woah我 – 2015-04-02 21:22:53

22

事實上,這不是標準的C++標準,所以我們必須查看語言歷史的年代來找到無效的點。

在1989年,當進一步定義「C++」,因爲根據在1985年該名稱其原始以來,Stroustrup的宣稱基初始化已經從該語言的早先化身改變,爲了應對多繼承:[1]

[p191] The C++ Programming Language [Stroustrup 1986] describes C++ as defined and implemented in August 1985. This paper describes the growth of the language since then and clarifies a few points in the definition. It is emphasized that these language modifications are extensions; C++ has been and will remain a stable language suitable for long term software development. The main new features of C++ are: multiple inheritance, type-safe linkage, better resolution of overloaded functions, recursive definition of assignment and initialization, better facilities for user-defined memory management, abstract classes, static member functions, const member functions, protected members, overloading of operator -> , and pointers to members. These features are provided in the 2.0 release of C++.

[p214]The syntax for initializing base classes and members has been extended to cope with multiple inheritance and the order of initialization has been more precisely defined. [..]

文中繼續演示了我們目前熟悉的基類初始化語法,正如Sneftel已經指出的那樣(省去了尋找更多舊文檔的麻煩!),但這並不是最遲在1985年,在最初的C++實現中,它本身是從「C with Classes」演化而來的。因此,我們可以得出結論C++ 2.0在1989年引入了更爲熟悉的語法,並且這個「過時的」版本在此之前是有效的。

注意,當然,在問題的代碼中,沒有基數。因此,即使在C++ 1.0中,該程序最終也沒有成功編譯。但是,我們已經發現了爲什麼這種語法正在被解析。

GCC正在診斷在C++近三十年來一直未被證實的模糊,長期被遺忘的語法。


[1] 「C++的演化:1985年至1989年」,Bjarne的Stroustrup的,AT & T貝爾實驗室,1989; pdf

5

這在ARM的第18.3.2節中具體描述爲不合時宜。

這些功能的原因通常是爲舊版本的C++或帶類的C提供連續性。所有「時代錯誤」都具有不良的特徵。編譯器不需要提供這些功能,但如果他們這樣做,則必須允許程序員停用它和/或被警告使用它。

+1

在第一個例子中,你是否支持相當於A(int x):m(x){}'的聲明? – Sjoerd 2015-04-03 10:55:27

+1

@Sjoerd我不認爲有任何。基類名稱不是初始化語法的一部分的C++版本不允許類具有非默認構造的成員。 – Sneftel 2015-04-03 11:15:58