2016-04-08 3 views
1

Der tatsächliche Code ist komplexer, aber ich konnte es auf dieses Beispiel reduzieren.Vorlage statisch constexpr Definition von odr-used Variable

Alles funktioniert gut, bis ich versuche, einen Zeiger zu nehmen Typen MyPackets_t :: (uncomment call() in main() foo) für die Anwendung

An diesem Punkt zu verbinden, um erfordern Typen eine Definition .

Ich kämpfe mit der richtigen Syntax für die Definition. Kommentierte Vorlage ... sollte den Trick machen. Es erzeugt jedoch einen Fehler "Vorlagenargumente zu 'PacketCollection :: types' stimmen nicht mit der ursprünglichen Vorlage überein".

Der Versuch, so etwas wie dieses - template <> constexpr int PacketCollection :: Typen []; - verursacht einen weiteren Linker-Fehler, als würde die Variable in dieser Zeile verwendet und nicht deklariert.

Ich habe versucht, MyPackets_t anstelle von PacketCollection - gleiche Ergebnisse.

Wenn ich Paket Sammlung nicht-Templat machen dann kompiliert alles und läuft wie erwartet.

Ich fühle, dass ich entweder etwas sehr einfach hier fehlt bin, oder es ist ein Fehler in dem Compiler. Ich bekomme dieses Verhalten mit gcc 4.8 und 4.9.

Clang 3.5 hat eine sligtly andere Perspektive auf die Situation: Erklärung constexpr statisches Datenelement ‚Typen‘ einen Initialisierer erfordert.

Die einzige Lösung, die ich war bisher gefunden habe

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

stattdessen zu verwenden, aber ich diese Lösung nicht mögen. Wenn Variable in nicht-templateten Versionen arbeitet (unter Verwendung des Initialisierers aus dem Header), sollte sie auch für Templates funktionieren.

#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; 
} 

Antwort

2

sollten Sie T anstelle von Packet_A

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

Siehe live example.

+0

Vielen Dank! Das hat funktioniert. Gibt es einen Spezifikationsabschnitt, der erklärt, warum und wie das funktioniert? – Ghostrider

+0

@ Ghostrider Siehe z.B. [Temp.static]/1 aus dem [Entwurf Standard] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4582.pdf): 'template class X { statische T s; }; Vorlage T X :: s = 0; ' – TemplateRex