2012-01-19 7 views
5

Considerate questo esempio:Vector costruttore con due parametri viene analizzato come una dichiarazione di funzione

#include <iostream> 
#include <string> 
#include <vector> 
#include <iterator> 

int main() 
{ 
    std::string sen = "abc def ghi jkl"; 
    std::istringstream iss(sen); 

    std::vector<std::string> // declaration in question 
    vec(std::istream_iterator<std::string>(iss), 
     std::istream_iterator<std::string>()); 

    std::copy(vec.begin(), vec.end(), 
       std::ostream_iterator<std::string>(std::cout, "\n")); 
} 

Il compilatore genera un errore alla chiamata a std::copy

request for member 'begin' in 'vec', which is of non-class type...

posso andare in giro l'errore In questo modo:

std::istream_iterator<std::string> it_begin(iss); 
std::istream_iterator<std::string> it_end; 
std::vector<std::string> vec(it_begin, it_end); 

o mettendo tra parentesi ciascun parametro, in questo modo:

std::vector<std::string> 
vec((std::istream_iterator<std::string>(iss)), 
    (std::istream_iterator<std::string>())); 

o anche con la nuova inizializzazione uniforme in C++ 11:

std::vector<std::string> vec { /*begin*/, /*end*/ }; 

Perché compilatore analizzando la dichiarazione nell'esempio come una dichiarazione di funzione? Conosco la maggior parte delle analisi irritanti, ma ho pensato che ciò avvenga solo con elenchi di parametri vuoti. Mi chiedo anche perché la seconda soluzione funziona.

+0

GCC 4.6.1, se è importante. Ho anche provato con il compilatore online di comeau. – jrok

+0

Salvati digitando: 'std :: istream_iterator it_begin (iss), it_end; std :: vector vec (it_begin, it_end); ' –

+0

Domanda ben formata, ben costruita e ben formattata, on-topic e utile. Buon lavoro. :) –

risposta

9

È ancora l'analisi più irritante.

std::vector<std::string>      // return type 
vec(          // function name 
    std::istream_iterator<std::string>(iss), // param 1: an iterator called (iss), or just iss 
    std::istream_iterator<std::string>()  // param 2: unnamed function 
);           //   returning iterator 

Geordi dice:

<tomalak> << ETYPE_DESC(vec); std::vector<std::string> vec(std::istream_iterator<std::string>(iss), std::istream_iterator<std::string>()); 
<geordi> lvalue function taking a istream_iterator<string, char, char_traits<char>, long> , a pointer to a nullary function returning a istream_iterator<string, char, char_traits<char>, long> , and returning a vector of strings 

Il punto cruciale di esso, in realtà, è che i nomi dei parametri possono avere parentesi intorno a loro (vale a dire iss(iss)) senza alterare la semantica della dichiarazione. A volte.

Utilizzare un altro gruppo di parentesi che circonda anche il tipo, come mostrato, per forzare il primo parametro (e, di conseguenza, il secondo) da analizzare come espressione anziché come dichiarazione.


Se aiuta, prendere in considerazione anche:

void foo(int (x)) { 
    cout << x; 
} 

int main() { 
    foo(42); 
} 

Output is 42.

+0

@Als: la dichiarazione è perfettamente valida. Tuttavia è valido sia come dichiarazione di un vettore che come dichiarazione di funzione, e lo standard dice che quest'ultimo ha la precedenza. È la tua [analisi più irritante] di base (http://en.wikipedia.org/wiki/Most_vexing_parse). L'OP è semplicemente sorpreso che la sua dichiarazione sia una dichiarazione _function_ valida, a causa di quelle parentesi attorno al nome del primo argomento. –

+0

Err ... Forse, quelle parentesi sono ridondanti comunque si potrebbe mettere n di quelle parentesi e funzionerebbe ancora allo stesso modo. –

+0

@Als: Sì, esattamente. Questo è il punto. BTW il plurale è "parentesi". –

Problemi correlati