2017-08-02 90 views
1

我正在嘗試在constexpr中使用make_tuple()。它在全球範圍內運作。但它會爲static constexpr類成員生成鏈接錯誤。如何在靜態constexpr類成員中使用make_tuple()?

#include <iostream> 
#include <tuple> 

using namespace std; 

class A 
{ 
public: 
    static constexpr auto z = make_tuple(5, 3.0); 
}; 

constexpr auto tp = make_tuple(6, 3.2); 

int main() 
{ 

    cout << get<0>(tp) << " " << get<1>(tp) << endl; // OK 

    cout << get<0>(A::z) << " " << get<1>(A::z) << endl; // error: (.text+0x5a): undefined reference to `A::z' 
                  //  (.text+0x67): undefined reference to `A::z' 

} 

我已經檢查heremake_tuple它本身也不是一個c++11constexpr。我猜這在這種情況下不是問題。如果是的話,它會產生一個編譯錯誤,而不是鏈接錯誤。

我試圖定義constexpr類的外部波紋一樣通過this answer

class A 
{ 
public: 
    static constexpr tuple<int, double> z; 
}; 

constexpr tuple<int, double> A::z = make_tuple(5, 3.0); 

的建議不過,它會產生幾個編譯錯誤。這使得根據回答constexpr initializing static member using static function

static constexpr類成員中使用make_tuple的正確方法是什麼?

編譯器: g++ 4.8.4clang 3.4-std=c++11

+0

[很適合我](http://coliru.stacked-crooked.com/a/bc0d0fef61b17c97)。 – user0042

+0

悲傷地不與非內在的對象。使用靜態constexpr函數來傳遞對象。 –

+0

這個編譯器的g ++版本是什麼? – army007

回答

4

在C++ 11/14,static constexpr變量必須定義在需要它有一個的方式使用某處如果使用的ODR(使用的ODR手段」一個身份「,例如,給他們一個真正的參考或指針,ODR在這裏意味着」一個定義規則「,而ODR使用的意思是」在某種意義上使用,它要求它只有一個定義「,我縮短爲「有一個身份」)。

Simply add:

constexpr tuple<int, double> A::z; 

和我們定義它的存在。這需要恰好在一個編譯單元中。

在C++ 17中,添加了inline變量,我相信constexpr變量是隱式地內聯的。我不是C++ 17專家,但是沒有定義的it compiles and runs in C++1z mode,所以我的解釋似乎至少有一半是正確的。

inline變量,如inline功能,在結束了該定義創建的任何地方編譯就是了。inline功能通常由具有與特殊說明的每個目標文件的定義,當有人需要它的一個地址,則實施重複在鏈接時被丟棄,每個人都指最後一個站點。我不知道inline變量傾向於以相同的方式實現)

如果你想在C++ 11中解決這個問題而無需在硬編碼模板參數.cpp文件change z to a constexpr function中添加內容,並在需要時使用它。


正如SergyA提到,ODR這裏觸發,因爲get返回參考一個字段中的元組,並參考暗示的身份必須存在的領域,因此整個數組。

從理論上講,按價值返回的精心製作的value_get可以避免此ODR的使用,但它取決於tuple的實現,因爲它反過來不能調用get

+2

我只是補充說,這裏的ODR使用情況是由於get <>返回一個引用的事實。我想,應該可以做my_get <>返回值,這不會觸發問題。 – SergeyA

+0

*定義*,未聲明。隱式內聯僅適用於靜態數據成員。 –

+0

@ yakk感謝您解釋它是如何違反ODR和建議使其具有「constexpr」功能。 – army007