2012-09-19 211 views
7

foo.h中:靜態常量類成員聲明

class Foo 
{ 
public: 
    Foo(); 
    static const unsigned int FOOBAR = 10; 
    static const unsigned int BARFOO = 20; 

private: 
    unsigned int m_FooBar; 
    bool m_Bar; 
    void Bar(); 
}; 

在Foo.cpp中:

Foo::Foo() 
    : m_FooBar(FOOBAR), // this works 
     m_Bar(false) 
{ 
} 

void Foo::Bar() 
{ 
    //m_FooBar = m_Bar ? FOOBAR : BARFOO; // linker fails *1 
    m_FooBar = FOOBAR; // ok 
} 

我與GCC 4.5.3編譯。有沒有任何理由說明爲什麼鏈路* 1未註釋時鏈接器會失敗?

Foo.o: In function 'Foo::Bar' (name unmangled): 
Foo.cpp: undefined reference to `Foo::FOOBAR' 
Foo.cpp: undefined reference to `Foo::BARFOO' 

試用VC2005,2008,2010和CB2010。他們都編譯並鏈接好。爲什麼GCC在這種情況下失敗?

鑑於answer here,爲什麼其他流行的編譯器不像GCC那樣失敗?無論如何,它必須是一個bug,無論是GCC還是其他流行的編譯器。還是有更合理的解釋?

+3

嗯...它在VS2010編譯得很好。 – Mysticial

+0

編譯和鏈接CB2010和VS2005 –

+1

@Mysticial問題是關於gcc,但。我可以確認鏈接器錯誤。 –

回答

4

形式上,頭只聲明靜態常量,他們也必須定義(至少在C++ 03中)。但是,如果你只使用他們的價值觀,你通常會擺脫這種困境。

在C++ 11中,當靜態爲「odr-used」時,更正式地指定爲需要定義。 *1行就是一個例子。三元操作符試圖形成對值的引用,而編譯器(或鏈接器實際上)意識到它不能。


的C++ 11標準說

9.4.2靜態數據成員
§3...
人員應仍然在如果它命名空間範圍來限定 在程序中被使用(3.2),名稱空間範圍定義不應該包含初始化程序

+0

但在C++中03如果聲明並在頭文件中定義了整數靜態常量,就像在問題 –

+0

中一樣,如果您只是使用它們的值,那麼它們都很好。三元運算符產生對兩個值中的一個的引用,當它們未被定義時這是不可能的。如果您嘗試通過引用某個函數來傳遞其中一個值,您會得到類似的效果。 –

+0

那麼爲什麼其他流行的編譯器不這樣做呢?如果三元操作員這樣做,它不應該在VC2010上失敗嗎? –

0

嘗試確定這些成員:

static const unsigned int FOOBAR = 10; 
static const unsigned int BARFOO = 20; 

外班宣言。

Foo::FOOBAR = 10; 
Foo::BARFOO = 20;