2014-12-23 13 views
5

Come esercizio di apprendimento sto costruendo una classe per gestire i vecchi valori di argc e argv su main. Sto memorizzando argv come std :: vector di std :: stringhe. Per il momento vorrei riagganciare il mio oggetto come se fosse il vettore. Il problema che sto avendo è che la mia soluzione diventa altamente dipendente dalla mia scelta di contenitore e il compilatore si rompe quando provo a risolverlo. Osservare:Tipo automatico per metodo automatico non riuscito. Perché?

Questo è il modo in cui vorrei che la mia classe lavorasse per questo esempio.

int main(int argc, char* argv) { 
    CLI options(argc, argv); 

    for (auto option : options) { 
    cout << option << endl; 
    } 
} 

Questo è abbastanza banale, ma ha richiesto un momento di ricerca. Ecco il mio file di intestazione

typedef char* cstring; 

class CLI { 
    std::vector<std::string> arguments; 
public: 
    CLI(const int argc, const cstring argv[]); 

    std::vector<std::string>::const_iterator begin(); 
    std::vector<std::string>::const_iterator end(); 
}; 

e il mio file sorgente per la classe CLI. (meno include ecc.)

CLI::CLI(const int argc, const cstring argv[]) { 
    arguments = std::vector<std::string>(argv, argv + argc); 
} 

std::vector<std::string>::const_iterator CLI::begin() { 
    return arguments.begin(); 
} 

std::vector<std::string>::const_iterator CLI::end() { 
    return arguments.end(); 
} 

Questo funziona magnificamente, ma qui è il mio primo problema. Se decido che desidero utilizzare una lista collegata al posto di un vettore, ora ho almeno cinque punti che devono essere modificati, più se il mio codice cliente sta avendo una giornata stupida e non usa l'auto per il suo ciclo (o qualsiasi altra cosa altrimenti lo fa). Sembra che dovrebbe essere un caso di auto-soccorso! Con le nuove funzioni C++ dovrei essere in grado di cambiare la firma del metodo a questo:

... // Header 
auto begin(); 

... // Source 
// Possibly without the decltype now? Not sure how or when... 
auto CLI::begin() -> decltype(arguments.begin()) { 
    return arguments.begin(); 
} 

Questo è dove ho finalmente ottengo un errore:

.../main.cpp: In function ‘int main(int, char**)’: 
.../main.cpp:10:22: error: use of ‘auto CLI::begin()’ before deduction of ‘auto’ 
    for (auto option : options) { 
        ^
.../main.cpp:10:22: error: invalid use of ‘auto’ 

Va bene. Se dovessi indovinare cosa significasse, direi che l'auto nel ciclo for sta cercando la firma per il metodo begin, sperando di trovare un tipo di ritorno concreto. Quello che trova invece è auto e panico.

Quindi, questa teoria è corretta, e c'è un modo migliore per nascondere il tipo di contenitore nonostante gli iteratori?

P.S. Più guardo a questo problema, più mi sto rendendo conto che questa funzionalità probabilmente non è la funzionalità che voglio comunque nel prodotto finale. Ma questa sembra ancora un'opportunità per imparare qualcosa.

+1

Perché non semplicemente 'std :: vector opzioni (int argc, const char * const * argv) {return {argv, argv + argc}; } '? – Casey

+0

Perché in futuro mi piacerebbe poter usare questa classe per analizzare internamente le opzioni. In questo modo potrei avere metodi 'bool' per ogni opzione invece di doverli cercare esternamente. – Jwashton

risposta

2

Dal momento che l'intestazione non include il codice, l'unità di compilazione per main.cpp non può dedurre il significato di auto per begin()

Questo potrebbe funzionare meglio per ciò che si intende:

header.h

#include <vector>                 

class A { 
public: 
     std::vector<int> a; 
     decltype(a.begin()) begin(); 
     decltype(a.cbegin()) cbegin() const; 
}; 

Header.cpp

#include "header.h" 
decltype(A::a.begin()) A::begin() { 
     return a.begin(); 
} 
decltype(A::a.cbegin()) A::cbegin() const { 
     return a.cbegin(); 
} 

main.cpp

#include "header.h" 
int main(int argc, char **argv) { 
     A a; 
     auto b = a.begin(); 
     auto cb = a.cbegin(); 
     return 0;                
} 

Una nota sulla sicurezza const: ricordare che un "const_iterator" è un unico tipo che non è necessariamente const stessa, ma che l'oggetto che rappresenta è const. Ciò significa che il tipo è diverso e impedisce di restituire a.begin() all'interno di una funzione const.L'ingenuo potrebbe provare ad aggiungere il tipo di reso const decltype(a.begin()) ma non è ancora un vector::const_iterator ma piuttosto uno const vector::iterator.

+0

Ah! Grazie! Catture interessanti Presumibilmente inlineing questi piccoli metodi risolverebbe quindi il problema. Un altro pensiero però, posso cambiare la dichiarazione del metodo per includere il postfix di tipo restituito? 'auto begin() -> decltype (arguments.begin());' Di nuovo, probabilmente non vale la pena questa volta, ma buono a sapersi. – Jwashton

+1

Perché non avere solo il decltype invece dell'auto? – inetknght

+0

Perfetto! Ho anche scoperto che posso chiamare 'cbegin()' invece di 'begin()' in modo da ottenere ancora un const_iterator. Lo stesso risultato tutt'intorno. Grazie! =) – Jwashton

Problemi correlati