2015-07-22 8 views
9

Ich möchte die CRTP pattern in Kombination mit einem Sperrmechanismus für die Zugriffssynchronisierung in Multithread-Umgebung verwenden.Vorlage Definition von Nicht-Vorlage Fehler

Mein Code sieht wie folgt aus:

//-- CRTP base class with some sync/lock mechanism 
template<typename T, typename SYNC> 
struct Base { 
    static std::unordered_map<int, std::string> s_map; 
    static SYNC s_sync; 
}; 

//-- derived class using CRTP 
template<typename SYNC> 
struct ProductX : public Base<ProductX<SYNC>, SYNC> {}; 

//-- static initialisation 
template<typename SYNC> 
std::unordered_map<int, std::string> Base<ProductX<SYNC>, SYNC>::s_map { 
    { 1, "value_1" }, 
    { 2, "value_2" } 
} 

Allerdings bekomme ich

error: template definition of non-template std::unordered_map<int, std::basic_string<char> > Base<ProductX<SYNC>, SYNC>::s_map

beim Kompilieren.

Der Fehler wird bei der Initialisierung der statischen s_map ausgelöst. Kann mir jemand zeigen, was ich falsch mache?

+0

@Deduplicator - dies ist kein Duplikat dessen, was Sie markiert haben. Wenn Duplikat von etwas, dann von diesem: http://stackoverflow.com/questions/13404695/c-how-to-initialize-static-variables-of-a-partial-template-specialization –

Antwort

0

C++ ermöglicht dies:

template<typename SYNC> 
std::unordered_map<int, std::string> Base<ProductX<SYNC>, SYNC>::s_map { }; 

nur mit teilweisem Template-Klasse Spezialisierung entspricht. Um dies zu tun, überprüfen Sie bitte Antworten von Columbo und n.m. Benutzer unten. Nachteil ist jedoch, dass Sie für jede ProductX Klasse, die Sie auf diese Weise erstellen, alles neu definieren müssen. Ie. in meinem Fall, wenn ich Klassen ProductX, ProductY, ProductZ erstellen möchte, muss ich teilweise Spezialisierung für jede von ihnen definieren, einschließlich aller Mitgliedsfunktionen usw., die IMHO nicht sehr praktisch ist.

Falls wir nicht wollen, ganze Klasse Spezialisierung zu schreiben, haben wir entweder statischen Variable ohne-spec Template-Definition verwenden:

template<typename T, typename SYNC> 
std::unordered_map<int, std::string> Base<T, SYNC>::s_map { }; 

oder ganz spezielle Template-Definition:

struct NoSync { }; 
template<typename NoSync> 
std::unordered_map<int, std::string> Base<ProductX<NoSync>, NoSync>::s_map { }; 
Hier

ist voll Beispiel mit voller Template-Spezialisierung:

//-- CRTP base class with some sync/lock mechanism 
template<typename T, typename SYNC> 
struct Base { 
    static std::unordered_map<int, std::string> s_map; 
    static SYNC s_sync; 
    static std::string& value_name1(int value) { return s_map[value]; } 
}; 

//-- derived class using CRTP 
template<typename SYNC> 
struct ProductX : public Base<ProductX<SYNC>, SYNC> {}; 

struct NoSync {}; 

//-- static initialisation 
template<> 
std::unordered_map<int, std::string> Base<ProductX<NoSync>, NoSync>::s_map { 
    { 1, "value_1" }, 
    { 2, "value_2" } 
}; 

int main() { 
    ProductX<NoSync> p; 
    std::cout << "Value: " << p.s_map[1] << "\n"; 
    std::cout << "Value: " << p.value_name1(2) << "\n"; 
} 

Dieser wird gut kompilieren.

Ich möchte Columbo und 'n.m."Für ihre Antworten und dafür, dass sie mich in die richtige Richtung weisen! Ich würde Ihre Antworten auswählen, aber ich wollte diese Lösung zeigen, ohne die Spezialisierung der Klassenvorlage zu schreiben.

+0

Col ** u ** mbo. Da ist ein Du in der Mitte. – Columbo

+1

@Columbo Nicht, wenn er ein [Sri Lanka] (https://en.wikipedia.org/wiki/Colombo) Fan ist ... – Barry

+0

@Barry Ich schätze die Forschung, aber mein Name ist immer noch Columbo. Ich nenne dich nicht 'Berry', weil ich auch gerne spazieren gehe. ;-) – Columbo

7

Sie verwenden Base<ProductX<SYNC>, SYNC> als Mitglieder Spezialisierung in der Definition von s_map, so dass Sie tatsächlich benötigen eine entsprechende Teil Spezialisierung von Base (§14.5.5.3/1). Mit anderen Worten: Sie versuchen, ein Mitglied einer nicht existierenden Teilspezialisierung zu definieren.

versuchen, diese Spezialisierung bieten:

template<typename SYNC> 
struct ProductX; 

//-- CRTP base class with some sync/lock mechanism 
template<typename T, typename SYNC> 
struct Base {}; 
template<typename SYNC> 
struct Base<ProductX<SYNC>, SYNC> { 
    static std::unordered_map<int, std::string> s_map; 
    static SYNC s_sync; 
}; 

//-- derived class using CRTP 
template<typename SYNC> 
struct ProductX : public Base<ProductX<SYNC>, SYNC> {}; 

//-- static initialisation 
template<typename SYNC> 
std::unordered_map<int, std::string> Base<ProductX<SYNC>, SYNC>::s_map { 
    { 1, "value_1" }, 
    { 2, "value_2" } 
}; 

Demo.

+0

Vielen Dank für Ihre Antwort Columbo ! Du hast recht und hast mich in die richtige Richtung gezeigt. Allerdings ist das Schreiben der Template-Klassen-Spezialisierung in meinem Fall nicht sehr praktisch, da ich alles für jedes von mir erstellte ProductX neu schreiben muss. Siehe meine Antwort unten für weitere Details. –

4

Ein vereinfachtes Beispiel.

template <class A, class B> 
struct C 
{ 
    static int x; 
}; 

template <class A, class B> int C<A, B>::x = 0; // this works 

jedoch

template <class A> int C<A, double>::x = 0; // same error as yours 

letztere Definition gehört zu einer partiellen Spezialisierung von C, die nicht existiert. Erstellen Sie eine:

template <class A> 
struct C<A, double> 
{ 
    static int x; 
}; 

template <class A> int C<A, double>::x = 1; 

und alles ist wieder gut.

+0

Danke für Ihre Antwort! Als Columbo hast du mich in die richtige Richtung gewiesen. Siehe meine eigene Antwort unten für weitere Details. –