2012-01-27 9 views
10

Si consideri il seguente semplice mappa:Come esprimere una stringa letterale all'interno di un modello parametrizzato dal tipo di caratteri utilizzati per rappresentare il letterale?

class MyCoolMap : public unordered_map<const char *, const char *> 
{ 
public: 
    ProtoTypeMap() 
    { 
    insert(value_type("in1", "out1")); 
    insert(value_type("in2", "out2")); 
    ... 
    insert(value_type("inN", "outN")); 
    } 
}; 

Ora, supponiamo che io bisogno di fare questa mappa disponibile sia per char e wchar_t stringhe. Così, riscrivo come segue:

template<class C> 
class MyCoolMap : public unordered_map<const C *, const C *> 
{ 
public: 
    MyCoolMap() 
    { 
    insert(value_type("in1", "out1")); 
    insert(value_type("in2", "out2")); 
    ... 
    insert(value_type("inN", "outN")); 
    } 
}; 

E, naturalmente, questo non funziona per C=wchar_t. Il problema è che non so come definire la differenza tra i valori letterali char e i valori letterali wchar_t. In questo momento vedo due soluzioni, entrambe brutte.

Soluzione 1 - specializzarsi MyCoolMap per wchar_t:

template<> 
class MyCoolMap<wchar_t> : public unordered_map<const wchar_t *, const wchar_t *> 
{ 
public: 
    MyCoolMap() 
    { 
    insert(value_type(L"in1", L"out1")); 
    insert(value_type(L"in2", L"out2")); 
    ... 
    insert(value_type(L"inN", L"outN")); 
    } 
}; 

Questo è un male, perché tutta la logica è duplicato.

Soluzione 2 - a tratti come soluzione:

#define _TOWSTRING(x) L##x 
#define TOWSTRING(x) _TOWSTRING(x) 

template <class C, int> struct special_string; 
#define DECL_SPECIAL_STRING(STR) \ 
const int ss_##STR = __LINE__; \ 
template<> struct special_string<char, ss_##STR> { static const char *get_value() { return #STR; } }; \ 
template<> struct special_string<wchar_t, ss_##STR> { static const wchar_t *get_value() { return TOWSTRING(#STR); } }; 

DECL_SPECIAL_STRING(in1) 
DECL_SPECIAL_STRING(out1) 
DECL_SPECIAL_STRING(in2) 
DECL_SPECIAL_STRING(out2) 
... 
DECL_SPECIAL_STRING(inN) 
DECL_SPECIAL_STRING(outN) 

template<class C> 
class MyCoolMap : public unordered_map<const C *, const C *> 
{ 
public: 
    MyCoolMap() 
    { 
#define INSERT_MAPPING(in, out) insert(value_type(special_string<C, ss_##in>::get_value(), special_string<C, ss_##out>::get_value())) 
    INSERT_MAPPING(in1, out1); 
    INSERT_MAPPING(in2, out2); 
    ... 
    INSERT_MAPPING(inN, outN); 
#undef INSERT_MAPPING 
    } 
}; 

In questo modo non ho bisogno di replicare la logica, ma questo è così prolisso e si basa molto sulle macro.

Ci deve essere un modo migliore; Io proprio non lo vedo.

Sto usando VS2010.

EDIT

Sono contento che una soluzione molto più semplice, si propone - i crediti vanno a https://stackoverflow.com/users/5987/mark-ransom. Ho dovuto fare piccole correzioni per farlo compilare, però:

#define _TOWSTRING(x) L##x 
#define TOWSTRING(x) _TOWSTRING(x) 

template<typename C> const C * ChooseCW(const char * c, const wchar_t * w); 
template<> const char * ChooseCW<char>(const char * c, const wchar_t * w) 
{ 
    return c; 
} 
template<> const wchar_t *ChooseCW<wchar_t>(const char * c, const wchar_t * w) 
{ 
    return w; 
} 

#define CW(C, STR) ChooseCW<C>(#STR, TOWSTRING(#STR)) 

Grazie ancora.

+0

+1 Bello. :) –

+2

Il tuo problema è che mentre i due elenchi di stringhe * si assomigliano * l'un l'altro, non sono proprio gli stessi. – egrunin

risposta

9

Utilizzare una macro per generare entrambe le forme della stringa e una funzione modello per scegliere quale utilizzare.

template<typename C> 
const C * ChooseCW(const char * c, const wchar_t * w); 

template<> 
const char * ChooseCW<char>(const char * c, const wchar_t * w) 
{ 
    return c; 
} 

template<> 
const wchar_t * ChooseCW<wchar_t>(const char * c, const wchar_t * w) 
{ 
    return w; 
} 

#define CW(C, STR) ChooseCW<C>(STR, L##STR) 

insert(value_type(CW(C, "in1"), CW(C, "out1"))); 
+0

Semplice, come tutto ciò che è geniale. Il tuo snippet di codice richiede alcune modifiche per renderlo compilabile, pubblicandoli come una modifica alla mia domanda. Ma altrimenti: semplicemente meraviglioso. – mark

+0

@mark, grazie per i complimenti e grazie per aver segnalato gli errori nel mio codice. Spero che questo compili ora, anche se non è identico al tuo. –

-1

fare tutte le costanti stringa membri statici, qualcosa di simile:

#include "stddef.h" 
#include "stdio.h" 
template<class C> 
class String 
{ 
    public: 
    String(const C* value = defVal) : mValue(value) {} 
    const C* valueOf() { return mValue; } 
    private: 
    const C* mValue; 
    static const C defVal[]; 
}; 
const char String<char>::defVal[] = "char"; 
const wchar_t String<wchar_t>::defVal[] = L"wchar_t"; 
int main(int argc, char **argv) 
{ 
    String<char> c(*argv); 
    String<wchar_t> w; 
    return printf("%S\n", w.valueOf()); 
} 

probabilmente si potrebbe macroise le definizioni per evitare di duplicarli.

+0

Non è esattamente quello che ha fatto? –

Problemi correlati