2015-07-22 25 views
9

Desidero utilizzare CRTP pattern in combinazione con un meccanismo di blocco per la sincronizzazione dell'accesso in ambiente multithread.Definizione modello di errore non modello

Il mio codice è simile al seguente:

//-- 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" } 
} 

Tuttavia ottengo

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

durante la compilazione.

L'errore viene generato per l'inizializzazione statica s_map. Qualcuno può indicarmi cosa sto facendo male?

+0

@Deduplicator - questo non è un duplicato di ciò che hai contrassegnato. Se duplicato di qualcosa, allora di questo: http://stackoverflow.com/questions/13404695/c-how-to-initialize-static-variables-of-a-partial-template-specialization –

risposta

0

C++ permette questo:

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

solo con corrispondenti parziale specializzazione classe template. Per fare ciò, si prega di controllare le risposte di Columbo e nm. utenti di seguito. Tuttavia, lo svantaggio è che devi ridefinire tutto per ogni classe ProductX che crei in questo modo. Vale a dire. nel mio caso, se voglio creare le classi ProductX, ProductY, ProductZ, dovrò definire una specializzazione parziale per ognuna di esse, incluse tutte le funzioni membro ecc., che non è molto pratico IMHO.

Nel caso in cui non vogliamo scrivere tutta la classe di specializzazione, dobbiamo utilizzare sia variabile statica senza-spec definizione del modello:

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

o completamente specializzata definizione del modello:

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

Qui è pieno esempio con piena modello di specializzazione:

//-- 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"; 
} 

Questo compilerà bene.

Vorrei ringraziare Columbo e il giorno'per le loro risposte e per avermi indicato nella giusta direzione! Selezionerei le tue risposte, ma volevo mostrare questa soluzione senza scrivere la specializzazione del modello di classe.

+0

Col ** u ** mbo. C'è qualcuno nel mezzo. – Columbo

+1

@Columbo A meno che non sia un fan [Sri Lanka] (https://en.wikipedia.org/wiki/Colombo) ... – Barry

+0

@Barry Apprezzo la ricerca, ma il mio nome è ancora Columbo. Non ti chiamo 'Berry' perché mi piace anche il brambling. ;-) – Columbo

7

Si utilizza Base<ProductX<SYNC>, SYNC> come specializzazione membri nella definizione di s_map, quindi è effettivamente necessaria una corrispondente specializzazione parziale di Base (§14.5.5.3/1). In altre parole, si sta tentando di definire un membro di una specializzazione parziale inesistente.

Prova a condizione che la specializzazione:

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

Grazie per la risposta Columbo ! Hai ragione e mi hai indicato nella giusta direzione. Tuttavia, scrivere la specializzazione di classe template non è molto conveniente nel mio caso, poiché devo riscrivere tutto per ogni ProductX che creo. Vedi la mia risposta qui sotto per maggiori dettagli. –

4

Un esempio semplificato.

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

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

Tuttavia

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

Quest'ultima definizione appartiene ad una specializzazione parziale di C che non esiste. Crea uno:

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

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

e tutto va bene ancora.

+0

Grazie per la tua risposta! Come Columbo, mi hai indicato nella giusta direzione. Vedi la mia risposta qui sotto per maggiori dettagli. –

Problemi correlati