Ciekawostka - błąd w g++ 4.9.2

0

Piszę sobie program (kolejny eksperyment ze Sztucznej Inteligencji). Mam kompilator g++ 9.3.1. Wszystko działa poprawnie. Zachciało mi się to skompilować pod g++ 4.9.2 (mam go na starym laptopie, z systemem Fedora Core 21). I okazało się, że to się nie kompiluje, chociaż powinno wspierać C++ 14 (a dodałem flagę -std=gnu++14). Minimalny case jest taki:

#include <vector>
#include <iostream>
int main()
{
    std::vector<int> x={1,2,3};
    for (auto y{x.begin()}; y!=x.end(); y++)
    { 
        std::cout << *y << "\n";
    }
    return 0;
}

Natomiast jeśli zmienić linię 6 na:

    for (auto y(x.begin()); y!=x.end(); y++)

... wówczas kompiluje się bez zarzutu. Jedyna różnica to te nawiasy klamrowe - powinny być okrągłe. Ale w nowych C++ podobno zaleca się klamrowe przy wywołaniu konstruktora.

2

Nie rozumiem czego ty oczekujesz: GCC 4.9.2 zostało wydane 30 października 2014, ergo w sposób naturalny wsparcie dla C++14 jest ograniczone.
Ba zapewne ta wersja gcc ma braki ze C++11 (twój przypadek).

Mamy rok 2021 rok temu wszedł standard C++20 i jako że to dużo zmienia obecne kompilatory mają słabiutkie wsparcie dla tej wersji i jeszcze długo nie będę go używał w moim obecnym projekcie (c++17 poszło szybko, bo było kosmetyczne).

Żywe demo

Poza tym jakie jest pytanie?

1

Czy jesteś pewien, że poprawiona wersja robi to co myślisz, że robi?
Nie chce mi się sprawdzać, ale o ile dobrze pamiętam były kiedyś jazdy z std::vectorem.

std::vecor v{3} robiło vector z jednym elementem inicjalizowanym "3"
std::vector v(3) robiło vector z trzema elementami inicjalizowanymi "0"

2

Problemem jest bardziej auto niż nawiasy, bo następujący kod się kompiluje:

#include <vector>
#include <iostream>

int main()
{
    std::vector<int> x={1,2,3};
    for (std::vector<int>::iterator y{x.begin()}; y!=x.end(); y++)
    { 
        std::cout << *y << "\n";
    }
    return 0;
}

W oryginale błąd jest:

<source>: In function 'int main()':
<source>:7:30: error: no match for 'operator!=' (operand types are 'std::initializer_list<__gnu_cxx::__normal_iterator<int*, std::vector<int> > >' and 'std::vector<int>::iterator {aka __gnu_cxx::__normal_iterator<int*, std::vector<int> >}')
     for (auto y{x.begin()}; y!=x.end(); y++)
                              ^

Czyli w momencie porównania, a nie inicjalizacji. Najwyraźniej to co wyszło z auto nie było tym czego oczekiwalibyśmy.

Zwróć uwagę w błędzie na na fragment std::initializer_list - w sumie to przed tym cię ostrzegałem. Nawias klamrowy doprowadził do skonstruowania "initializer list" zamiast wywołania konstruktora.

To chyba było prawidłowe działanie w starych wersjach, gdzie {jeden_element} nadal było wywołaniem initilizer_list,a tylko (jeden_element) konstruktora jednoparametrowego. Potem to usunięto.

0

Tak jeszcze dopiszę, bo to ciekawostka:

Wygląda na to, że pokazany problem został uznany za defekt w specyfikacji C++11 i retroaktywne (czyli zmieniając wstecznie specyfikacje C++11) usunięty w grudniu 2014. Najwyraźniej poprzez przełączenie inicjalizacji {jeden_element} na konstruktor kopiujący:
https://stackoverflow.com/questions/33970892/list-initialization-priority-from-object-of-same-type

Także to chyba jeden a przypadków retroaktywnych zmian w specyfikacji powodujących, że stary kompilator ma problem - został napisany dla specyfikacji, która mu się zmieniła.

0

Jakiś powód by tak wydziwiać, zamiast normalnego auto y = x.begin(), ewentualnie auto y = begin(x)?

0
Azarien napisał(a):

Jakiś powód by tak wydziwiać, zamiast normalnego auto y = x.begin(), ewentualnie auto y = begin(x)?

Wiele powodów zostało wyłożonych ładnie w "The Nightmare of Initialization in C++".
W skrócie: przejdźmy na {}, świat będzie lepszy a bugów mniej.

1 użytkowników online, w tym zalogowanych: 0, gości: 1