2013-05-06 7 views
16

Czy jest prawnie zadeklarować zmienną pętli w pętli for opartej na zakresie z tą samą nazwą, której używam w wyrażeniu wyrażenia pętli? Mam nadzieję, że przykład ten wyjaśnia.Identyfikator o tej samej nazwie zarówno w wyrażeniu, jak i deklaracji opartej na zakresie dla

#include <iostream> 
#include <vector> 

struct bar { 
    std::vector<int> nums; 
}; 

int main() 
{ 
    bar b; 
    b.nums = {1, 2, 3}; 

    for(int b : b.nums) 
     std::cout << b << std::endl; 
} 

gcc 4,8 daje błąd, podczas gdy clang 3.2 pozwala na to.

+5

[Zgłoszono błąd do gcc] (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54430). –

+0

@JesseDobra Dzięki za to kopanie. Okazuje się, że nie znalazłem nic na bugzilli, ponieważ szukałem "opartego na bazie" zamiast "opartego na zasięgu". Nie wiem, jak ten termin zamanifestował się w mojej głowie, ten sam błąd też się zdarzył w tytule. – inf

Odpowiedz

11

Z mojego czytania C++ 2011 6.5.4, Twój kod:

bar b; 

for(int b : b.nums) 
    std::cout << b << std::endl; 

powinny być zamienione na:

bar b; 

{ 
    auto && __range = b.nums; 
    for (auto __begin = __range.begin(), __end = __range.end(); __begin != __end; ++__begin) { 
     int b = *__begin; 
     std::cout << b << std::endl; 
    } 
} 

mi to oznacza, że ​​dzyń jest poprawna.

+0

IMHO, powiedziałbym, że jest to usterka standardu. Widoczność 'int b' powinna być od': 'aż do końca instrukcji for. – rodrigo

+0

@rodrigo: Zgodziłem się, dopóki nie pomyślałem o tym więcej. Co to znaczy: 'for (auto & x: x)'? –

+0

Byłoby to tak samo bezsensowne jak zwykła deklaracja "auto &x = x;" iz tych samych powodów. – rodrigo

9

Clang ma rację:.

§ 6.5.4/1 C++ 11 standard określa zasięg oparte for instrukcji w następujący sposób:

Dla zasięg oparte dla instrukcji postaci

for (for-range-declaration : expression) statement 

pozwolić zakres inicjalizacji równoznaczne z wyrażeniem w nawiasie

(expression) 

i dla zakres oparte do zestawienia postaci

for (for-range-declaration : braced-init-list) statement 

niech zakres-startowych być równoważna usztywnione-init-listy. W każdym przypadku, zakres oparty na rachunku odpowiada do

{ 
    auto && __range = range-init; 
    for (auto __begin = begin-expr, 
      __end = end-expr; 
      __begin != __end; 
      ++__begin) { 
     for-range-declaration = *__begin; 
     statement 
    } 
} 

Z powyższego widać, że zmienna b, co odpowiada for-range-declaration została zadeklarowana wewnątrz zagnieżdżonej instrukcji bloku, natomiast inicjator range-init (który odpowiada b.nums) pojawia się w zakresie nadrzędnym, gdzie b powinien zostać rozwiązany na obiekt typu bar.

+0

Ale 'b' w * range-init * będzie błędnym' b'. –

+0

@ftopbit: Masz rację, początkowo to przeoczyłem. Edytowałem odpowiedź, dziękuję –

+3

To nie jest takie łatwe ... z dosłownego interpretowania standardu, w 'auto && __range = range-init;' 'range-init' jest w rzeczywistości' b.num', ale 'int b' nie wchodzi w definicję aż do 5 linii później ...Ale znowu, widząc oryginalny kod, należałoby oczekiwać, że 'int b' ukrywa' bar b'. – rodrigo

2

Co jest warte, ten błąd został już naprawiony w gcc trunk. :)

+0

Świetne do słuchania: D – inf