2014-02-25 78 views
1

對於下面的代碼,爲什麼沒有重新聲明Foo :: bar的第一個主要工作正常工作,而第二個功能需要它?C++靜態constexpr成員重新聲明以外的類

struct Foo{ 
static constexpr int bar = 30; 
}; 
//Declaration of Foo::bar outside of struct 
constexpr int Foo::bar; 
int returnconstexpr(const int& x) { return x; } 

int main() 
{ 
    //Ok without declaration outside of struct 
    std::cout << Foo::bar << std::endl; 

    //Requires declaration outside of struct 
    std::cout << returnconstexpr(Foo::bar) << std::endl; 

    //Here static constexpr works as a definition 
    static constexpr int x = 2; 
    std::cout << returnconstexpr(x) << std::endl; 

    return 0; 
} 

我假定這是因爲在第一種情況下,編譯器真的只是堅持的價值,而在第二種情況下,功能要求其不存在沒有重聲明的地址。如果是這樣,那麼我所說的是聲明實際上是一個定義?我對此感到困惑,因爲在課堂上提供了一個初始化程序,但它並不是一個定義。例如,第三個案例工作得很好。

回答

1

我假定這是因爲在第一種情況下,編譯器 真的只是堅持的價值,而在第二種情況下, 功能需要它還不存在不重複聲明 的地址。如果是這樣,那麼我所說的是 聲明實際上是一個定義?

您已經回答了問題。靜態成員是定義的以外的類,所以你有什麼是一個定義。當你傳遞給函數時,地址是必需的,因此你需要定義靜態成員。在第一種情況下,編譯器只需用該值替換Foo::bar

現在改變函數簽名如下:

int returnconstexpr(int x) { return x; } 

在上述情況下,您將不再需要的定義。

此規則是在C++標準的3.2:

變量X,其名稱顯示爲潛在評估表達 EX是ODR-使用,除非x是滿足要求的對象 用於出現在常數表達式(5.19)中並且ex是表達式e的潛在結果的集合的元素,其中 左值到右值轉換(4.1)被應用於e,或者e被丟棄了 值表達式(第5章)。

在上述情況下,立即應用一個左值到右值的轉換,因此它不會被使用(如標準所述)並且不需要定義。簡而言之,這意味着它只能使用該值並且不需要知道地址,但是當您使用引用類型(const int &)時,需要編譯器知道對象在內存中的位置。

+0

正確的,這是有道理的,否則每次包含標題,它都會提供一個新的定義。謝謝。 – JamesLens

+0

@JamesLens:對,爲了防止C++強制你在類之外定義靜態成員。 –