2011-07-15 59 views
5

我幾乎對所有東西都使用typedefs,包括函數。在過去的幾周裏,我一直在調整我們的C++代碼,使其最終草稿(N3242)作爲指導,儘可能符合ISO C++ 11標準。使用默認參數的C++函數的多重聲明

正如我們所知,偶爾會有多個聲明通過externs出現在多個文件或重複的typedefs中進入我們的代碼。據第7.1.3節,上面DOCO 145頁的摘錄,這應該是無害的:

3. In a given non-class scope, a typedef specifier can be used to redefine the name of any type declared in that scope to refer to the type to which it already refers.

[ Example:

typedef struct s { /* ... */ } s; 
    typedef int I; 
    typedef int I; 
    typedef I I; 

— end example ]

所以,我寫了一個程序來測試這一點。在最簡單的形式:

typedef int (fcntype)(int, int); 
extern fcntype fcn1; 

int fcn1(int x, int y) { return x + y; } 

int main(int argc, char ** argv) { return fcn1(2, 3); } 

編譯使用gcc與

-Wfatal-errors -Wswitch-default -Wswitch-enum -Wunused-parameter -Wfloat-equal -Wundef -c -Wstrict-null-sentinel -std=c++0x -pedantic -Wall -Wextra 

有,當然沒問題。讓我們來重複decl函數:

typedef int (fcntype)(int, int); 
extern fcntype fcn1; 
extern fcntype fcn1; // woops. probably from an #include ... 

int fcn1(int x, int y) { return x + y; } 

int main(int argc, char ** argv) { return fcn1(2, 3); } 

正如標準預測的那樣,沒有問題。讓我們對原文做出不同的改變:

typedef int (fcntype)(int, int=0); // default param. 
extern fcntype fcn1; 

int fcn1(int x, int y) { return x + y; } 

int main(int argc, char ** argv) { return fcn1(2); } // use the default param 

再次,沒有問題。問題來了,當我們有重複的東方電氣和這樣的默認的參數都:

typedef int (fcntype)(int, int=0); // default param. 
extern fcntype fcn1; 
extern fcntype fcn1; // FYI this is line 3 in the error message below. 

int fcn1(int x, int y) { return x + y; } 

int main(int argc, char ** argv) { return fcn1(2); } // use the default param 

和GCC與

decltest.cpp:3: error: default argument given for parameter 2 of ‘int fcn1(int, int)’ 

當然抱怨,我清理代碼的方式應該是清理,這就是說我正在將decl合併爲一個更好的組織文件。但是,這是編譯器中的一個錯誤,還是我對一個默認參數「是」的誤解?

回答

6

首先,對於具有相同類型的相同函數聲明,最多隻能有一個定義默認參數的聲明。這是由於§8.3.6[dcl.fct.default]/4:

... A default argument shall not be redefined by a later declaration (not even to the same value). [ Example:

... 
void m() { 
    void f(int, int);  // has no defaults 
    f(4);     // error: wrong number of arguments 
    void f(int, int = 5); // OK 
    f(4);     // OK, calls f(4, 5); 
    void f(int, int = 5); // error: cannot redefine, even to same value 
} 
... 

end example ] ...

此外,如@Sven注意到,默認參數將不會出現在一個typedef,雖然克++不能與-pedantic甚至抓住它。我認爲clangVisual C++拒絕這個,但我沒有嘗試過。

+2

此外,腳註101(在同一頁上):「這意味着默認參數不能出現,例如,在函數指針聲明,對函數的引用或typedef聲明中。所以我認爲'typedef int(fcntype)(int,int = 0);'本身已經不能編譯。或者我錯過了什麼? – Sven

+0

啊,是的。特別感謝您參考標準。我突出了它。令人着迷的是,這些東西是如何在你身上蔓延的,這是一段時間內通過代碼來清理事情的很好的論據。 –

1

您的標準報價不適用於此,因爲您沒有多次聲明typedef,而是多次使用它。

默認參數確實是一個棘手的情況,它們只能出現在一個聲明中(並且記住,定義本身計算爲聲明,即使將默認參數同時放在前向聲明和定義中也是錯誤的)。

0

這會產生相同的錯誤:

extern int fcn1(int, int=0); 
extern int fcn1(int, int=0); 

所以這並不奇怪你typedef版本不起作用。