2011-07-27 74 views
10

我最近看到這個代碼在一個C++項目源文件正在使用:使用命名空間std的順序;幷包括?

using namespace std; 
#include <iostream> 

忽略的它是否有using namespace std在所有好主意的所有問題,就是上面的代碼,甚至合法的嗎?在這兩行之前,文件中沒有代碼。

我原以爲這不會編譯,因爲namespace std直到#include <iostream>指令將它包含到文件中才被聲明爲範圍,但是使用編譯系統來編譯這個項目就好了。如果有人鏈接到規範的相關部分,那將是最受讚賞的。

+1

這段代碼是寫在源文件還是頭文件?也許它是由另一個聲明名稱空間「std」的文件包含的。 –

+0

這是在源文件中,而不是頭文件。這是一個很好的理由澄清! – templatetypedef

+0

clang ++給出了一個警告:using指向隱式定義的名稱空間'std'; –

回答

5

一個可能有趣的數據點。當我編譯如下:

using namespace std; 
using namespace no_such_namespace; 

與G ++ 4.5.2,我得到:

c.cpp:2:17: error: ‘no_such_namespace’ is not a namespace-name 
c.cpp:2:34: error: expected namespace-name before ‘;’ token 

無論std也不no_such_namespace已經被定義爲在該點命名空間,而G ++只抱怨第二。我沒有認爲在沒有聲明的情況下,標識符std有任何特殊之處。我認爲@James Kanze是正確的,這是g ++中的一個bug。

編輯:(!5年前)And it's been reported.

更新:現在是8年多了,仍然沒有被分配給任何人,更不用說固定。 g ++ 4.9.2出現問題。鐺++ 3.5沒有,但它發出了std和警告致命錯誤no_such_namespace

c.cpp:1:17: warning: using directive refers to implicitly-defined namespace 'std' 
using namespace std; 
       ^
c.cpp:2:17: error: expected namespace name 
using namespace no_such_namespace; 
       ^
1 warning and 1 error generated. 
2

從SO/IEC 14882:2003

[7.3.3.9]通過using聲明聲明的實體應在上下文使用它根據其在使用聲明的點定義已知。 當使用名稱時,不考慮使用聲明後添加到名稱空間的定義。給定X :: m(其中X是用戶聲明的名稱空間)或給定:: m(其中X是全局名稱空間),設S爲所有聲明的集合除了在任何命名空間(包括直接包含m的一個或多個聲明的X)中忽略using指令之外,在X中使用 - 指令提及的所有命名空間的所有命名空間的傳遞閉包中。在查找名稱時不會搜索多次命名空間。如果S是空集,則該程序不合格。否則,如果S只有一個成員,或者該引用的上下文是使用聲明(7.3.3),則S是m的所需聲明集。否則,如果使用的m不是一個允許爲s選擇了一個獨特的聲明,該程序是形成不良的

所以,如果它發生在工作,這是一個僥倖,不便於攜帶。

+0

突出顯示的部分表示該聲明應該沒有效果,但並不能解釋它是否合法。 –

+1

查看這部分規範,似乎這是指使用'std :: cout'或'std :: string'形式'使用'聲明,而不是像'using namespace std'。 – templatetypedef

1

此代碼是未定義的行爲[lib.using.headers]:

翻譯單元應只包括外部的任何外部聲明或定義的報頭,並應所述第一參考之前詞法包含頭它在該翻譯單元中聲明或首先定義的任何實體。

您參考std,然後包含聲明它的標頭。即使這仍然是未定義的行爲:

#include <string> 
using namespace std; 
#include <iostream> 
+0

對不起,沒有看到這是如何適用。哪部分被特別違反? 'using namespace std;'不是一個封閉的外部聲明或定義。它不是對頭中聲明或定義的實體的引用。 – MSalters

+1

@ MSalters:它是對頭中聲明的實體(名稱空間標準)的引用。來自[basic]:「一個實體是一個值,對象,引用,函數,枚舉器,類型,類成員,模板,模板特化,**命名空間**,參數包或this。 – ybungalobill

+0

@ybungalobillL:謝謝,現在清楚。 – MSalters

3

我不認爲這是合法的,但標準不是100%清楚它。 基本上,名稱查找(定義在§3.4)找不到以前的 聲明的命名空間,因爲沒有一個。一切 取決於是否:

using namespace std; 

是命名空間與否的聲明。而且我在 第7.3.4節中看不到任何文字,它說using-directive聲明瞭命名空間 。 G ++允許你的代碼,但恕我直言,這是一個錯誤。

1

我覺得有標準(包括C++ 0x中)的一個漏洞對於這種情況。

我們在3.3.6節([basic.scope.namespace]):

一個命名空間定義的聲明區域是它的命名空間體。原始名稱空間名稱表示的潛在作用域是由相同聲明區域中的每個名稱空間定義與原始名稱空間名稱建立的聲明區域的連接。據稱在名稱空間體中聲明的實體是名稱空間的成員,並且由這些聲明引入名稱空間的聲明性區域的名稱被稱爲名稱空間的成員名稱。名稱空間成員名稱具有名稱空間範圍。它的潛在範圍包括名稱的聲明點(3.3.2)之後的名稱空間;對於指定成員名字空間的每個使用指令(7.3.4),成員的潛在作用範圍包括遵循成員聲明點的使用指令潛在範圍的那部分。

翻譯單元的最外層聲明地區也是一個名字空間,叫做全局命名空間。全局名稱空間中聲明的名稱具有全局名稱空間作用域(也稱爲全局作用域)。這種名稱的潛在範圍從宣告點(3.3.2)開始,到宣告區域的翻譯單位結束時結束。具有全局名稱空間作用域的名稱被稱爲全局名稱。

所以namespace std是全局命名空間中的一員,而這個名字的範圍在點聲明的開始。

和3.3.2([basic.scope.pdecl])告訴我們:

申報的名點立即爲它的完整說明符(第8章)後和它的初始化之前(如果有的話),除了下面提到。

沒有一個例外適用於名稱空間。

因此,名稱空間名稱不能在其聲明符之前使用,但名稱空間名稱不是聲明符。哎呀。

0

最近我面臨同樣的問題,並被我的技術主管建議,使用名稱空間不保證方法的可見性,直到具有相關方法的名稱空間包含在使用.h文件的文件中。包含頭文件的 解決了問題。