2016-04-08 79 views
1

實際代碼更復雜,但我能夠將其降低到此示例。模板odr使用變量的靜態constexpr定義

一切工作正常,直到我試圖用一個指針指向MyPackets_t ::類型(取消註釋調用到foo()在main())

在這一點上,以使應用程序鏈接,類型需要一個定義。

我正在努力與定義的正確語法。評論出模板...應該做的伎倆。然而,它產生了一個錯誤「PacketCollection :: types的模板參數與原始模板不匹配」。

嘗試這樣 - 模板<> constexpr int PacketCollection :: types []; - 導致另一個鏈接器錯誤,就像在該行中使用變量而不是聲明一樣。

我試過使用MyPackets_t而不是PacketCollection - 結果相同。

如果我將數據包集合設置爲非模板化,那麼所有內容都按預期進行編譯和運行。

我覺得我要麼丟失了一些非常基本的東西,要麼在編譯器中存在一個錯誤。我用gcc 4.8和4.9得到這個行爲。

對於這種情況,Clang 3.5有一個很不同的看法:constexpr靜態數據成員'類型'的聲明需要一個初始化器。

是我發現的唯一的解決方法到目前爲止是使用

static constexpr std::array<int, 2> types() { return {1,2}; } 

代替,但我不喜歡這種解決方案。如果變量工作在非模板版本(使用頭部的初始化器),它也應該適用於模板化的工作。

#include <iostream> 

using namespace std; 

class Packet_A 
{ 
public: 
    static constexpr int TYPE = 1; 
}; 

class Packet_B 
{ 
public: 
    static constexpr int TYPE = 2; 
}; 

template <typename T> class PacketCollection 
{ 
public: 
    static constexpr size_t size = 2; 
    static constexpr int types[size] { 1, 2 }; 
}; 

typedef PacketCollection<Packet_A> MyPackets_t; 

//template<typename T> constexpr int PacketCollection<Packet_A>::types[PacketCollection<Packet_A>::size]; 

void foo(const int* bar, size_t size) 
{ 
    if (size >= 2) 
    { 
     cout << bar[0] << bar[1]; 
    } 
} 

int main(int argc, char* argv[]) 
{ 
    cout << Packet_A::TYPE; 
    cout << MyPackets_t::types[0]; 

    //foo(MyPackets_t::types, MyPackets_t::size); 

    return 0; 
} 

回答

2

您應該使用的T代替Packet_A

template<typename T> constexpr int PacketCollection<T>::types[PacketCollection<T>::size]; 
                ^      ^

live example

+0

謝謝!這工作。是否有一個說明部分解釋了爲什麼以及如何工作? – Ghostrider

+0

@Ghostrider請參閱來自[標準草案](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4582.pdf)的[temp.static]/1:'template class X { 靜態T s; }; template T X :: s = 0;' – TemplateRex