2016-03-03 21 views
10

Ho appena scritto una semplice funzione di utilità per std :: string. Poi ho notato che la funzione sarebbe esattamente la stessa se lo std::string fosse un std::wstring o un std::u32string. È possibile utilizzare una funzione di modello qui? Non ho molta familiarità con i modelli, e std::string e std::wstring sono modelli stessi, il che potrebbe essere un problema.È possibile scrivere una funzione per std :: string e std :: wstring?

template<class StdStringClass> 
inline void removeOuterWhitespace(StdStringClass & strInOut) 
{ 
    const unsigned int uiBegin = strInOut.find_first_not_of(" \t\n"); 

    if (uiBegin == StdStringClass::npos) 
    { 
    // the whole string is whitespace 
    strInOut.clear(); 
    return; 
    } 

    const unsigned int uiEnd = strInOut.find_last_not_of(" \t\n"); 
    strInOut = strInOut.substr(uiBegin, uiEnd - uiBegin + 1); 
} 

È un modo corretto per farlo? Ci sono insidie ​​con questa idea. Non sto parlando di questa funzione, ma del concetto generale di utilizzare una classe di modelli StdStringClass e di chiamare le solite funzioni std::string come trovare, sostituire, cancellare, ecc.

+1

I non vedo nulla di particolarmente sbagliato. Per me, il nostro modello sembra buono. Nessun problema per l'utilizzo di alcune funzioni specifiche. Semplicemente non si compila se dai un parametro che non ha usato la funzione all'interno del template – Garf365

+1

'find' e' replace' richiederà qualche trucco, dal momento che i tipi di caratteri sono diversi. Ad esempio, la funzione precedente non funzionerebbe per 'std :: wstring', perché' std :: wstring :: find_first_not_of' non accetta un 'const char *', ma un 'const wchar_t *'. –

+1

Seem sta bene per me, tranne invece che per 'unsigned int', raccomando di usare' typename StdStringClass :: size_type' o auto se C++ 11 è abilitato. – Radek

risposta

6

È una buona idea, ma vorrei creare il modello in cima di std::basic_string piuttosto che generale StdStringclass

template<class T> 
inline void removeOuterWhitespace(std::basic_string<T>& strInOut) 
{ 
    constexpr auto delim[] = {T(' '),T('\t'),T('\n'),T(0)}; 
    const auto uiBegin = strInOut.find_first_not_of(delim); 

    if (uiBegin == std::basic_string<T>::npos) 
    { 
    // the whole string is whitespace 
    strInOut.clear(); 
    return; 
    } 

    const auto uiEnd = strInOut.find_last_not_of(delim); 
    strInOut = strInOut.substr(uiBegin, uiEnd - uiBegin + 1); 
} 

vorrei anche fosso lo stile di MSDN "inout" notazione Favro per il nome più semplice come str. il programmatore si indovina che strè il risultato poiché viene passato come riferimento non const e la funzione restituisce void.

inoltre, ho cambiato unsigned int in auto. tutti i contenitori/stringhe C++ standard restituiscono size_t quando restituiscono gli indici. size_t potrebbe non essere unsigned int. auto corrisponde automaticamente al valore restituito corretto.

+0

Si suppone che 'T (0)' sia 'T ('')'? – Fabian

+0

dovrebbe essere il terminatore null. guardando di nuovo ho dimenticato lo spazio bianco, lo aggiungerò –

+0

Vedo. Ottima risposta. Sfortunatamente, C++ 11 non è disponibile per me. Spero di poter aggirare 'auto'. Il compilatore gcc si è lamentato quando uso 'size_t' qualche tempo fa, quindi sono passato a' unsigned int'. – Fabian

-1

Supponendo che il modello funzioni come previsto (non controllato ... scusa), un'altra opzione sarebbe quella di avvolgere la funzione in classe e controllare quali tipi di classi di stringhe si desidera applicare alla funzione per l'utilizzo costruttori.

EDIT: aggiunto quadro illustrativi

EDIT2 uno che compila (almeno con vs2015) :-)

class StringType1; 
class StringTypeN; 

class str { 

    //template function 
    template<class StdStringClass> 
    inline void removeOuterWhitespace(StdStringClass & strInOut) 
    { 
     //. 
     //. 
     //. 
    } 

public: 
    //constructors 
    str(StringType1 &s1) { removeOuterWhitespace(s1); } 
    //. 
    //. 
    //. 
    str(StringTypeN &sN) { removeOuterWhitespace(sN); } 


}; 

int main() { 

    return 0; 
} 

Edit3 Prova di concetto

#include <iostream> 
class incr { 
    //template function 
    template<class incrementor> 
    inline void removeOuterWhitespace(incrementor & n) 
    { 
     n++; 
    } 
public: 
    //constructors 
    incr(int &n1) { removeOuterWhitespace(n1); } 
    incr(double &n1) { removeOuterWhitespace(n1); } 
    incr(float &n1) { removeOuterWhitespace(n1); } 
}; 

int main() { 
    int n1 = 1; 
    double n2 = 2; 
    float n3 = 3; 
    std::cout << n1 << "\t" << n2 << "\t" << n3 << std::endl; 
    auto test1 = incr(n1); 
    auto test2 = incr(n2); 
    auto test3 = incr(n3); 
    //all variables modified 
    std::cout << "all variables modified by constructing incr" << std::endl; 
    std::cout << n1 << "\t" << n2 << "\t" << n3 << std::endl; 
    return 0; 
} 
+0

Si prega di elaborare ulteriormente e aggiungere del codice per illustrare la risposta. Rght ora non è una risposta utile, in quanto non fornisce una soluzione definitiva al problema OP. –

+0

Supponendo di aver capito bene, non vedo come questo ridurrebbe la duplicazione del codice. Nella classe, avrei ancora bisogno di implementare il codice sopra per ogni tipo di stringa. Il mio obiettivo è attenersi al principio ASCIUTTO. L'utilizzo di un metodo modello mi sembra molto più elegante. – Fabian

+0

Fabian, @Revolver_Ocelot, ho modificato la risposta e aggiunto codice illustrativo. Fabian, sì, so che c'è un po 'di codice in più, ma il vantaggio è che ottieni il controllo. Saluti! –

Problemi correlati