2017-01-22 101 views
4

此代碼在Visual Studio 2015更新3(此處爲visual C++ compiler online,並且在其他編譯器中我沒有在線嘗試過(GCC和CLANG),給出了一個重新聲明錯誤C++ 11在基於範圍的循環中重新聲明

vector<int> v = {1,2,3}; 
for (auto i : v) { 
    printf("%d ", i); 
    int i = 99; 
    printf("%d ", i); 
} 

輸出:1 99 2 99 3 99

VS C++編譯器的在線(版本:19.10.24903.0)警告有關此:

警告C4456:「我」隱藏以前的本地聲明

是否有在C++ 11規範一些空間,讓這兩種方案是有效的聲明?

在我看來,VS2015正在爲「自動i」創建一個範圍,併爲循環體創建一個範圍。

增加一個額外的範圍,因爲一個同事建議,編譯在我所測試過的其他的編譯器罰款(不,我想這一點,它只是出於好奇):

vector<int> v = {1,2,3}; 
for (auto i : v) {{ 
    printf("%d ", i); 
    int i = 99; 
    printf("%d ", i); 
}} 

感謝

編輯: 好吧,看完這個問題Redeclaration of variable in range-based for loops和「Angew」的答案後,我相信VS其實是正確的。

我讀這裏:cpp reference

鑑於這種語法描述:

for (range_declaration : range_expression) loop_statement 

,什麼這相當於:

{ 
auto && __range = range_expression ; 
for (auto __begin = begin_expr, __end = end_expr; 
    __begin != __end; ++__begin) { 
    range_declaration = *__begin; 
    loop_statement 
} 
} 

我明白loop_statement實際上是我的整個包括括號的塊,所以重定義確實在一個內部塊中,因此是有效的。

編輯2: 我最後的編輯,以供將來參考,讀傳統for循環語法是類似的情況(cpp for loop)作爲基於範圍的:

for (init-statement condition(optional); iteration_expression(optional)) statement 

「上述語法產生的代碼等同於:」

{ 
    init_statement 
    while (condition) { 
    statement 
    iteration_expression ; 
    } 
} 

所以回過頭來看,我也解釋/解析陳述作爲我的內在塊,包括大括號,對此,我至少會期望一個始終如一的行爲,在這個行爲中,我是編譯器。但是所有的編譯器都會爲傳統的for循環重新聲明錯誤。

+1

我剛剛看到這個其他問題http://stackoverflow.com/questions/24526131/redeclaration-of-variable-in-range-based-for-loops,其中指出VS實際上是正確的 – francholi

+0

for循環相當於while,你已經切斷了它後面的EXCEPT部分,它討論了標識符的作用域 – Cubbi

回答

5

N4606(C++ 17草案)3.3.3 basic.scope。塊,第4節說

名稱在 初始化語句 宣佈,該 的範圍申報 ,並在 條件的 如果 , 而 , 爲 ,和 開關 語句是本地的 如果 , 而 , 爲 ,或 開關 語句(包括控制聲明), ,不得以該語句的後續狀態也不在最外層塊中重新聲明(或者,對於 的 如果 聲明,任何最外塊的)的受控陳述;見6.4

縮短:在宣佈

名稱...換範圍聲明......是當地的第...,不得在隨後的重新聲明該聲明的條件也沒有在最外面的塊

我讀這是說它不應該被允許。

+0

但是你可以在嵌套的上下文中重新聲明它,對吧? – HolyBlackCat

+0

我會接受這個答案作爲參考,儘管在不同的實現中如何解釋這個語法是不一致的,這至少是令人不安的。謝謝。 – francholi

+1

我也很驚訝編譯器在幾年後仍然不同。但是,再一次,這是關於如何閱讀「聲明或最外面的塊」。如果這適用於range-for的直接聲明,那麼MSVC是正確的,但如果它適用於該位置的塊,那麼GCC/Clang是正確的。 – dascandy

0

C++ 11規範中是否有一些空間允許兩個實現有效?

只有一個例外,唯一的答案是否定的。

全局變量例外,您可以使用範圍操作符::來達到它們。否則,如果你shadow外部範圍內的變量的名稱,你不再有權訪問它。

+0

問題在於陰影本身的合法性,而不是陰影變量的可訪問性。 – Oktalist