2014-09-30 24 views
1

原問題

我想使用靜態成員變量爲了通過類型模板參數傳遞信息到模板類。這些變量不應該被包含在所有翻譯單元中的頭文件中設置,以便我可以在不重新編譯大部分目標文件的情況下更改它們。此外,對於不需要額外空間的變量,有一個方便的別名會很好。我認爲constexpr只讀樣哪些值可以分配給`constexpr`參考?

static constexpr const int& alias = T::static_variable_name; 

引用可以作爲這樣的別名,但不知道這是有效的。對於constexprreads

  • 構造參數或將被分配必須只包含文字值,constexpr變量和函數值的一個限制。

所以,我想它使用g++ -std=c++11並得到一種不一致的行爲對我的口味。代碼包含在這個問題的最後。在大多數的情況下,代碼編譯並運行正常,而是直接在非專業類模板使用h2g2_oracle::answer時(見註釋「錯誤,爲什麼?」),編譯失敗與消息

src/main.cpp:18:57: error: the value of ‘h2g2_oracle::_answer’ is not usable 
in a constant expression 
     static constexpr const int& answer = h2g2_oracle::answer; // ERROR; WHY? 
src/main.cpp:11:9: note: ‘int h2g2_oracle::_answer’ is not const 
     int h2g2_oracle::_answer = 42; 

爲什麼大多數constexpr引用都是作爲別名工作的,而這個單獨的引用不是?

#include <iostream> 

// a specific kind of oracle 
class h2g2_oracle { 
    protected: 
    static int _answer; 

    public: 
    static constexpr const int& answer = _answer; // public alias for reading 
}; 
int h2g2_oracle::_answer = 42; 

// some class template using a specific kind of oracle 
template<typename oracle> 
struct forecast { 
    // try to define an own alias 
    static constexpr const int& answer = oracle::answer; // works 
    //static constexpr const int& answer = h2g2_oracle::answer; // ERROR; WHY? 
}; 

// specialized version for the h2g2_oracle 
template<> 
struct forecast<h2g2_oracle> { 
    // also define the own alias 
    static constexpr const int& answer = h2g2_oracle::answer; // works 
}; 

int main() { 
    static constexpr const int& answer = h2g2_oracle::answer; // works 
    std::cout << answer << std::endl; 

    std::cout << forecast<h2g2_oracle>::answer << std::endl; 
    return 0; 
} 

尋址

@Ben福格特有關the gain of constexpr評論:是的,DYP is right with the assumption我喜歡的constexpr版本其體內的初始化。 長評論:我非常肯定,在單獨的翻譯單元中進行初始化會強制程序使用存儲原始值地址的某個內存位置。因此,我認爲constexpr可能對有用,總是在標題中(即模板(forecast<...>::answer)和非模板(h2g2_oracle::answer))具有靜態成員初始化。我知道我可以將非模板類更改爲包含一個虛擬模板參數,以便在頭中也可以完成初始化,但仍然最初對我來說,解決方案constexpr更容易。

@dyp關於possible g++ bug:啊,我沒想到找到一個這樣的「簡單」測試。現在我看到了相關的問題,這對我來說似乎是一個很好的解釋。任何可行的方法來確認/報告/幫助?如果你對此相當有信心,我至少可以接受這個答案。

關於definition before using @dyp:是的,我檢查了G ++是好的,在即使h2g2_oracle定義來的forecast定義後的非專業forecast使用oracle::answer。但是,當在main中使用forecast<h2g2_oracle>::answer時,h2g2_oracle必須是完成。這對我來說看起來很合理。其他想法:我更加着迷的是如何將靜態成員初始化爲另一個靜態成員(可能位於不同的翻譯單元)的引用方式。

關於

有趣@dyp,我不知道,如果你需要H2G2定義::答案預測使用它之前;它應該是odr-used(我覺得很奇怪)。

我想我現在明白了你的觀點。這也是我覺得有趣的地方:事實上,int h2g2_oracle::_answer = 42;甚至可以被移到不同的翻譯單位,它仍然有效。不知何故,鏈接器(即時簡單字)設法在需要的地方「插入」正確的內存地址h2g2_oracle::_answer

+0

目前還不清楚你認爲'constexpr'在這裏爲你做了什麼,但我寧願懷疑它不會以任何方式幫助你。 – 2014-09-30 13:32:57

+0

@BenVoigt'constexpr'允許在類體中定義。 – dyp 2014-09-30 13:48:23

+0

[鏗鏘++ 3.5不抱怨](http://coliru.stacked-crooked.com/a/34212c61d558c7a5) – dyp 2014-09-30 13:50:45

回答

2

簡單的解決方法是內聯和一定不需要存儲:

template<typename oracle> 
struct forecast 
{ 
    static const int& answer() { return h2g2_oracle::answer; } 
}; 

它也是C++ 98兼容。

+0

是的。事實上,將此稱爲解決方法實際上感覺很有趣,因爲這應該是傳統方式。作爲一個美學方面,我更喜歡一個可以作爲'foo(answer)'而不是'foo(answer())'傳遞的別名,但如果涉及到我遇到的複雜問題,則不會。 – Julius 2014-10-01 05:24:10

+0

然而,我仍然不願意接受這個答案,因爲我仍然對原始問題的答案感興趣。如果你不同意,請抱怨。 – Julius 2014-10-01 05:25:39

+0

@Julius:我完全理解這可能符合upvote的「有用」標準,但不被接受(這標誌着您的問題已得到解決)。 – 2014-10-01 12:47:37