2017-01-16 68 views
1

替換爲static const成員我跨代碼來這樣從程序員本人高度方面:優勢與靜態成員函數

class BigClass { 
    using MyId = uint32_t; 
    static constexpr MyId INVALID_ID() { return std::numeric_limits<MyId>::max();}; 
    class SmallClass { 
    /* Constructor, etc. */ 
    MyId id = INVALID_ID(); /* Default value */ 
    }; 
}; 

是否有任何明顯的優勢,定義INVALID_ID()爲函數而不是作爲一個靜態常量變量?

問題static constexpr variable vs function與我的問題完全相同(我使用uint32_t作爲示例,但我發現其他類型的問題也很有趣)。但是,我對這個問題的答案並不滿意。在閱讀了這裏的一些答案之後,我相信使用函數比使用簡單模板更有優勢。

+0

那麼,因爲它不是一個靜態成員變量,它不需要在類之外定義。 – NathanOliver

+1

@NathanOliver在使用ODR之前,IIRC靜態常量不需要定義。 – Quentin

+0

@Quentin Typo固定。他們可能會在這種情況下使用它。 – NathanOliver

回答

1

其中一個原因是,在這種形式下,不需要在類之外定義靜態成員,在類中實現頭的情況下,這是不可取的。

的第二個理由是可擴展性,你有一天想你的無效標識做在其初始化其他一些constexpr邏輯,除了調用諸如最大一個constexpr功能

+0

那麼,因爲這是一個整型常量,所以無論如何都不需要在類之外定義它。顯然,它不應該被用作左值,只要它不被用作左值,就不需要定義。 – AnT

+0

在我看來,這仍然是一個好習慣 – ZivS

+0

引用相反,如果靜態常量僅用作右值,那麼*不定義它是一個好習慣 - 它可以防止濫用它作爲左值。使定義成爲可選是C++規範中一個重要而且期待已久的補充。 – AnT

-1

我沒有看到任何優勢。我寧願將INVALID_ID聲明爲一個const(constexpr)而不是函數,因爲函數調用會讓讀者想知道正在進行什麼樣的計算。

+0

類似的問題被問到這裏:https://stackoverflow.com/questions/16287776/static-constexpr-variable-vs-function?noredirect=1&lq=1 –

+0

聲明是一個constexpr函數其中有零動態計算,而不是在任何其他聲明看到一個constexpr任何東西 – ZivS

1

這與線程安全和靜態初始化命令失敗有關。如果在單獨的翻譯單元中定義了兩個相互依賴的靜態變量(一個需要另一個翻譯單元的值來構建自身),則無法保證它們將被初始化的順序。

使用包裝函數和C++ 11保證編譯器將圍繞其初始化放置必要的線程鎖,函數local static將對該函數進行併發調用,等待變量在繼續執行之前進行初始化。

+0

你應該改變忘記做*這必須忘記與線程安全和靜態初始化順序失敗*? – NathanOliver

+0

是的,電話鍵盤沒有在猜測我想輸入什麼時得到了更好的... – rubenvb

+0

好的,我只是想檢查一下你是否搗碎了不同的句子, – NathanOliver

1

一個問題人們試圖通過更換類的靜態解決具有函數的常量成員是鏈接器錯誤。

例如:

struct A { 
    static constexpr int a = 1; 
}; 

void foo(int const&); 

foo(A::a); // Linker error: A::a. 

正確的解決方案是不拿指針或引用A::a(如果提供的A::a的外的線定義是不希望的):

void foo(int); 
+0

你可以拿指針。只需要定義'A :: a'。 –

+0

@NO_NAME定義'A :: a'可能不合需要。 –

2

除了簡單的編碼用法之外,我只能看到一個真正的區別:靜態常量變量只有在使用odr時才需要定義(用於以ref爲例的函數中...)。問題是,如果這個規則不被遵守,你會得到一個鏈接時間錯誤,程序員可能會浪費時間搜索問題的真正原因。

當您以這種方式使用某個函數,並嘗試將其作爲函數調用傳遞給需要ref的函數時,編譯時錯誤將立即在程序員的臉上顯現,並帶有明確的錯誤消息。所以我會說,這是更多的未來維護者友好...

+0

對未定義函數的調用可以像使用聲明的靜態全局一樣進行編譯。這兩個都會導致鏈接器錯誤。 – rubenvb