通過一個實例來引出本文要闡述的問題。具體的代碼為:
deque<string> test;
copy(istream_iterator<string> (cin), istream_iterator<string> (), back_inserter(test));
上面的代碼很明顯是先聲明了一個名為test的deque<string>容器,並將其初始化為空。然後,將從標准輸入流(cin)中讀入的以空格的一個個string推入容器,直到沒有更多可用的輸入為止。它等效於:
deque<string> test;
istream_iterator<string> first(cin) , last;
copy(first, last, back_inserter(test));
再看看使用下面的語句來聲明一個同樣的名為test的deque<string>容器。
deque<string> test(istream_iterator<string> (cin),istream_iterator<string> ());
我們寫出上面的語句的本意與之前的本意一樣,從標准輸入流(cin)中讀入的以空格的一個個string推入容器,直到沒有更多可用的輸入為止。不過我們是想通過調用deque<string>的接受一對迭代器為參數的構造函數來實現其功能。那麼它能完成我們設想的功能嗎?
其實”deque<string> test(istream_iterator<string> (cin),istream_iterator<string> ());“ 的功能只是聲明一個名為test的函數,並且其返回值類型為deque<string>,而需要傳入的參數有兩個,第一個是類型為 istream_iterator<string>而名為cin的參數,第二個為不接受任何參數的無名參數。它並沒有實現我們想要的“聲明一個名為test的deque<string>對象,並通過傳入的一對迭代器將其初始化”。為什麼會出現這種情況呢?
引用c++ 03標准的原話:當聲明和表達式語句兩者的語法形式之間可能出現二義性,即一個函數風格的顯式類型轉換作為其最左端的子表達式的表達式語句和一個其第一個聲明子以“(”開頭的聲明語句可能會無法區分開。在這種情況下,該語句被解釋為聲明。
簡而言之就是當出現了聲明與表達式二義性時,編譯器總是會將其決議為聲明。
那麼如何能夠避免出現這種問題呢?
既然這是由語法形式之間的二義性導致的,那麼就可以將該語句“修飾”為非法的聲明的語句從而消除其二義性。而想徹底的擺脫二義性,就不要使用那些會讓有些編譯器誤認為時聲明的語法形式。一般有兩種方法:
1.避免讓編譯器將其識別為一個函數聲明,直接的做法就是:
deque<string> test( (istream_iterator<string> (cin) ), ( istream_iterator<string> () ) );
通過給參數添加額外的括號,提示編譯器我們這裡提供的是構造函數而非參數聲明。冗余的括號使得這種形式的代碼不可能被解釋為合法的聲明語句。
2.使用具名變量作為構造函數的參數,徹底避免聲明語句產生二義性。
istream_iterator<string> first(cin) , last;
deque<string> test(first , last);
顯然方法2的代碼更佳清晰,而且更加便於維護。所以最好使用方法2來避免聲明與語句的二義性。