2015-04-11 11 views
5

Ich möchte ein statisches Array in einer Template-Funktion, deren Länge von dem Typ abhängt, auf den die Funktion spezialisiert ist. Mein erster Versuch war:Typabhängige Konstante in Template-Funktion

Rubrik:

template<typename T> 
struct Length { 
    const static size_t len; 
}; 

template<typename T> 
void func(){ 
    static T vars[Length<T>::len]; // len not const. according to compiler! 
    // ... 
} 

Quelldatei:

template<> const size_t Length<double>::len = 2; 
template<> const size_t Length<float>::len = 1; 
// ... 

Allerdings ist g++ dies nicht kompilieren und klagt

error: storage size of ‘vars’ isn’t constant

Also, was genau ist die Problem hier? Ich weiß, dass die Größe eines Array fester Länge eine Konstante sein muss und zur Kompilierungszeit bekannt sein muss, aber das scheint hier der Fall zu sein. Als ich

const size_t len = 2; 

void func(){ 
    static double vars[len]; 
} 

schreiben kompiliert es ohne Probleme.

Frage:

Was mit dem Code falsch ist und welche Alternativen gibt es für das gewünschte Verhalten zu erreichen? Ich möchte nicht den Speicher während der Laufzeit verteilen ...

Antwort

5

Für eine const Variable eine Kompilierung-Konstante (formal, eine konstanten Ausdruck) in Betracht gezogen werden, dessen Wert muss am Einsatzort zur Verfügung stehen. Das bedeutet, dass die spezialisierten Definitionen in die Header-Datei gehen müssten.

Wenn Sie als gerade Spezialisierungen des Mitglieds getan, wie Sie es getan haben, glaube ich, dass Sie einen Multiple-Definition-Fehler geben würde.

template<typename T> 
struct Length; 

template <> 
struct Length<double> 
{ 
    static const size_t len = 2; 
}; 

Als Randbemerkung, Ihr Programm war ursprünglich ungültig: Sie sollten mit Spezialisierung der gesamte Klasse-Vorlage, und hält die statische Element Definition Inline Ordnung sein eine explizite Spezialisierung muss vor der Verwendung deklariert werden. Das heißt, Sie müssten mindestens deklarieren die Spezialisierung von len in der Kopfzeile (oder überall wo Sie es verwenden wollten).

+0

Das Muster der Klassenvorlage der Spezialisierung wird ein metafunction genannt. Definitiv die richtige Lösung hier. – Potatoswatter

+0

Eine explizite Spezialisierung eines Mitglieds muss nicht vorher deklariert werden. Es wird die Member-Deklaration der enthaltenen Klassenvorlage übereinstimmen. – Potatoswatter

+0

@Potatoswatter Ich denke nicht, dass das eine Metafunktion ist. Laut [Boost.MPL] (http://www.boost.org/doc/libs/1_57_0/libs/mpl/doc/refmanual/metafunction.html) ist "A * metafunktion *" eine Klasse oder eine Klassenvorlage, die stellt eine zur Kompilierungszeit aufrufbare Funktion dar. " – Angew

1

Der folgende Code kompiliert für mich mit g++ 4.6.3 fein und erzeugt die Ausgabe

2 
1 

array.cpp:

#include <cstddef> 
#include <iostream> 

template<typename T> 
struct Length { 
    const static size_t len; 
}; 

template<typename T> 
void func(){ 
    static T vars[Length<T>::len]; 
    std::cout << (sizeof(vars)/sizeof(*vars)) << std::endl; 
} 

template<> const size_t Length<double>::len = 2; 
template<> const size_t Length<float>::len = 1; 

int main(){ 
    func<double>(); 
    func<float>(); 
} 
$ make array 
g++  array.cpp -o array 
$ ./array 
2 
1