標籤:

為什麼用了using namespace std會報錯?

#include &
#include &
#include &

using namespace std;

int main()
{
string str{"test!"};
find_if(str.begin(), str.end(), ispunct);
return 0;
}


這個程序在VS下是沒有問題的,而GCC會報錯。

問題的原因是C++里有三種ispunct(不考慮宏實現版本的話),編譯器不知道你要選擇哪一個。

一個是來自C的&里的ispunct。(C++標準允許C++標準庫header中將相對應的C庫函數定義在global scope上,也就是說即使你只包含了&,裡面也可能有C風格的不在std里的全局庫函數)

int ::ispunct(int c);

一個就是按照C++標準要放在std中的ispunct了,在&中。

int std::ispunct(int c);

然而還有一個是在&里的模板函數

template & charT std::ispunct(charT c, const locale loc);

如果你不加using namespace std,或者使用::ispunct,那麼選中的就會是第一個版本。

如果用std::ispunct或者using namespace std後直接ispunct,由於第二個和第三個都在std里,名字也一樣,編譯器就要想了這該選哪一個呢?

因為find_if是個模板函數,這時候編譯器自然要開始抱template argument deduction的大腿,指望從模板聲明中找出可用的篩選信息。

來看看find_if怎麼聲明的:

template&
InputIterator find_if (InputIterator first, InputIterator last, UnaryPredicate pred)

。。。這不坑爹嗎?pred參數啥限制條件也沒有怎麼判斷?

自然編譯器只能不知所措,被compile error淹沒了。

如果find_if長這樣:

template&
InputIterator maki (InputIterator first, InputIterator last, bool(*pred)(Nico))

那編譯器就可以判斷出來這裡第三個參數必須是個單參數的函數指針,就不會有歧義了。

等等,程序里不是沒包含&嗎,那怎麼會把第三個版本的ispunct也算進去?

是的,然而這不代表別的header不可以包含&

嘗試編譯以下程序:

#include &
#include &
#include &

using namespace std;

int main() {
bool(*p)(char, const locale) = ispunct; //強行選擇locale版本
}

這段程序在VS上是不通過的,而GCC可以編譯成功。

在GCC中,&和&其實都包含了一部分&的內容,這使得你只要包含了&或者&你就已經把locale版本的ispunct聲明也用到了,這樣編譯器自然不知道你要用哪一個版本。而VS中的這幾個頭文件中都沒有間接聲明到locale版ispunct,所以就會編譯失敗。

順便解釋下為什麼VS上直接ispunct不會發生前兩種ispunct的衝突。因為std::ispunct實際上是在namespace std中通過using ::ispunct實現的,也就是不論是ispunct也好還是::ispunct或者std::ispunct實際上調用的都是第一個版本,不存在歧義。


根據題主反饋的信息,Gomo Psivarh的回答是正確的,出錯的根源在於名字查找中的不確定。

原答案的解決方案仍是可用的,因為在lambda定義時說明了需要調用ispunct(int),從而消除了不確定。

---------以下是原回答-----------

ispunct()是&定義的一個函數。因為在C++里函數不是一等對象,編譯器不會把一個函數當作參數(實際這裡要求一個類的對象),所以報錯。

解決方法:用lambda把ispunct()封裝一下

find_if(str.begin(), str.end(), [](int i) {return ispunct(i);} );

我試了一下,編譯通過了,可是你沒有輸出,我也不知結果對不對。

與using namespace std;無關啊,難道你去掉了編譯能通過嗎?


ispunct是宏,不是真正的函數


推薦閱讀:

c++如何在編譯期判斷一個對象是否是字元串字面值?
C++的std::thread是怎麼進行參數傳遞的?
怎麼正確書寫C++高階函數?
你怎麼看 C++11(新的 C++ 標準)裡面的變化?

TAG:C | C標準 |