• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

istream_iterator

VPS Starter Arubacloud
0 głosów
557 wizyt
pytanie zadane 14 kwietnia 2017 w C i C++ przez Evelek Nałogowiec (28,960 p.)

Będą 2 pytania z C++:

1) Pierwsze pytanie: Czy jest sposób na zapisanie tego iteratora w taki sposób, aby wczytywał maksymalnie 5 liczb typu int? Na chwilę obecną dane są wczytywane dopóki nie wpiszę np. litery zamiast liczby, albo mam crash programu gdy wpiszę powyżej 5 liczb:

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;

int main() {
	vector <int> vec(5);
	copy(istream_iterator<int, char>(cin), istream_iterator<int, char>(), vec.begin());
}

Kombinowałem z użyciem copy_n(), ale nie jestem pewny, czy to poprawna funkcja do tej sytuacji:

copy_n(vec.begin(), 5, istream_iterator<int, char>(cin));

Dostaję w tej funkcji błąd o treści: "_Dest": nie można przypisać do zmiennej, która jest stałą.


2) Drugie pytanie: Próbowałem rozłożyć ten iterator:

copy(istream_iterator<int, char>(cin), istream_iterator<int, char>(), vec.begin());

na:

istream_iterator<int, char> in_iter_start(cin);
istream_iterator<int, char> in_iter_stop();
copy(in_iter_start(cin), in_iter_stop(), vec.begin());

ale podkreśla mi na czerwono copy(in_iter_start i wywala m.in. taki błąd:

  • Żadne wystąpienie elementu funkcja przeciążona "copy" nie jest zgodne z listą argumentów.

 Jak to można zrobić poprawnie?

1 odpowiedź

+2 głosów
odpowiedź 14 kwietnia 2017 przez mokrowski Mędrzec (156,260 p.)
wybrane 14 kwietnia 2017 przez Evelek
 
Najlepsza

1) W najbardziej zbliżonym do Twojego przykładu programu po poprawkach będziesz miał:

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>

using namespace std;
 
int main() {
    vector<int>vec(5);
    copy_n(istream_iterator<int>(cin), 5, vec.begin());
}

Tylko jak widzisz w kilku miejscach masz 5'tkę :-/ Lepiej chyba inaczej.. 

Aby dodawać do kontenera dane, powinieneś użyć insertera. Jest to back_inserter dla push_back() w kontenerze i front_inserter dla push_front(). Kontener vector ma mieć push_front więc program z copy_n będzie wyglądał tak:

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>

using namespace std;
 
int main() {
    vector<int>vec;
    copy_n(istream_iterator<int>(cin), 5, back_inserter(vec));
}

Plus rozwiązania z back_inserter(...) to przejrzystość zapisu. Minus to realokacje wykonywane przez kontener w tle (ale dla wartości 5, machnij na to ręką). Realokacji możesz uniknąć wywołując dla kontenera reserve().

Dla przykładu z begin() (czyli pierwszego), plus jest taki że kontener dostaje na samym wstępie wielkość więc nie będzie realokacji. 

2) Odpowiedziałem Ci już ... zrób zamiast vec.begin()   jako argument insert_iterator(vec)

Co do Twojego "char" (w <int, char>). Ten 2 argument jest domyślny. Stąd pytanie.. Co chcesz osiągnąć?

komentarz 14 kwietnia 2017 przez Evelek Nałogowiec (28,960 p.)

Dzięki Mokrowski, jak zawsze profesjonalnie. Pierwsze zrozumiałem. Jednak co do drugiego mam malutki problem. Zapisałem to w ten sposób:

istream_iterator<int, char> in_iter_start(cin);
istream_iterator<int, char> in_iter_stop();
copy(in_iter_start(cin), in_iter_stop(), insert_iterator<vector<int> >(new_vec, new_vec.begin()));

Jednak chyba czegoś nie rozumiem nadal, bo identyczny błąd dostaje: Żadne wystąpienie elementu funkcja przeciążona "copy" nie jest zgodne z listą argumentów.

 

Co do Twojego "char" (w <int, char>). Ten 2 argument jest domyślny. Stąd pytanie.. Co chcesz osiągnąć?

Pierwszy argument określa typ pobieranych danych, a drugi argument określa typ znaków używany przez ten strumień. (Alternatywą dla char jest podobno wchar_t).

komentarz 14 kwietnia 2017 przez mokrowski Mędrzec (156,260 p.)
edycja 14 kwietnia 2017 przez mokrowski

Bo *start i *stop to są już gotowe instancje. Próbujesz je w copy ponownie instancjonować? (BTW...mogło by się powieść gdyby miały operator()() ale nie mają :-)). Następną rzeczą jest insert. Rób go przez back_inserter(...) jak kontener docelowy (u Ciebie new_vec) nie ma alokowanej wielkości (czyli pamięci). Ma "upychać w nim dane". A jak już wielkość ma.. to po prostu new_vec.begin() i tyle :-)

I dalej.. znowu ten char.. on jest domyślny. Jak będziesz chciał iterować np. po UTF-8, to dotykasz tego argumentu szablonu. W Twoim przypadku nie wpisuj bo zaciemnia a początkujący wyciągnie wniosek że copy() nie działa bo są niezgodne typy...

istream_iterator<int> in_iter_start(cin);
istream_iterator<int> in_iter_stop();
copy(in_iter_start, in_iter_stop, back_inserter(new_vec);

A co do błędu.. Np dla clang++ 4.0 Twój kod pluje czymś takim:

ble.cpp:9:45: warning: empty parentheses interpreted as a function declaration [-Wvexing-parse]
    istream_iterator<int, char> in_iter_stop();
                                            ^~
ble.cpp:9:45: note: remove parentheses to declare a variable
    istream_iterator<int, char> in_iter_stop();
                                            ^~
ble.cpp:10:10: error: type 'istream_iterator<int, char>' does not provide a call operator
    copy(in_iter_start(cin), in_iter_stop(), insert_iterator<vector<int> >(new_vec, new_vec.begin()));
         ^~~~~~~~~~~~~
1 warning and 1 error generated.

Wydaje się sensowniejsze niż to co daje g++:

ble.cpp: In function 'int main()':
ble.cpp:10:27: error: no match for call to '(std::istream_iterator<int, char>) (std::istream&)'
     copy(in_iter_start(cin), in_iter_stop(), insert_iterator<vector<int> >(new_vec, new_vec.begin()));
                           ^

Czasem warto użyć "sprawdzarki online":  https://wandbox.org/

komentarz 14 kwietnia 2017 przez Evelek Nałogowiec (28,960 p.)

Tylko, że to co mi podajesz, czyli:

istream_iterator<int> in_iter_start(cin);
istream_iterator<int> in_iter_stop();
copy(in_iter_start, in_iter_stop, insert_iterator(new_vec);

nie działa.

Rozumiem, że w miejsce insert_iterator mam wstawić swój zdefiniowany iterator?

Już kombinuję jak mogę i wraz źle:

insert_iterator<vector<int> > insert_iter(new_vec, new_vec.begin());
istream_iterator<int> in_iter_start(cin);
istream_iterator<int> in_iter_stop();
copy(in_iter_start, in_iter_stop, insert_iter);

 

komentarz 14 kwietnia 2017 przez mokrowski Mędrzec (156,260 p.)
Moja wina, nie ten bufor schowka wkleiłem.. zobacz na poprawkę .. ma być back_inserter jak pisałem w treści. Ogólnie.. warto zapamiętać takie 80% prawdy :-/

Algorytmy z rodziny copy*, wymagają inserterów :-)
komentarz 14 kwietnia 2017 przez Evelek Nałogowiec (28,960 p.)
Nie no odpuśćmy, bo ciągle błąd. Może się nie da w ten sposób.

https://wandbox.org/permlink/Ot8a1Jzd1ndwr3Lq
komentarz 14 kwietnia 2017 przez mokrowski Mędrzec (156,260 p.)

Haaa :-) Tak to robisz :-) No to co jest zakończeniem strumienia który czytasz? Jeśli chcesz skończyć strumień to wciśnij w konsoli cmd Windows <ctrl+z> a w GNU/Linux <ctrl+d> w nowej linii po wprowadzeniu danych. To kończy strumień. Miałeś jeszcze błąd w linii którą skomentowałem:

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int main()
{
    vector <int> new_vec;
    istream_iterator<int> in_iter_start(cin);
    istream_iterator<int> in_iter_stop; // Tu nie może być () bo kompilator stwierdza że to.. deklaracja funkcji :-)
    copy(in_iter_start, in_iter_stop, back_inserter(new_vec));
}

Wprowadzenie danych:

13
45
909
<ctrl+d> // <- tu wciskam kombinację klawiszy :-)

To naprawdę działa jeśli podasz kilka liczb, oddzielisz je enterem lub znakiem białym i w nowej linii dasz wysłanie znaku EOF (to co napisałem wyżej). Inaczej program nie wie kiedy kończysz wprowadzać dane :-) Sprawdź. Skompiluj w systemie. Sprawdzarka nie wymaga "wciskania EOF" bo kończy strumień w sposób naturalny. https://wandbox.org/permlink/yV4KfszHEU2f8MGW

komentarz 14 kwietnia 2017 przez Evelek Nałogowiec (28,960 p.)

Heh... nareszcie działa... Dziękuje, można na Ciebie liczyć Mokrowski. Nawet chyba nie wiesz, jakiej frustracji człowiek dostaje jak kompilator odmawia współpracy. smiley

No to co jest zakończeniem strumienia który czytasz?

Według książki:

Wykorzystanie cin jako argumentu konstruktora oznacza, że funkcja używać będzie strumienia wejścia obsługiwanego przez cin. Brak argumentu drugiego konstruktora sugeruje błąd wejścia, więc powyższy kod pobiera dane ze strumienia wejścia do czasu natrafienia na znacznik końca pliku, napotkania danych niepoprawnego typu lub innego błędu wejścia.

Znam skróty Ctrl + D itd. tyle, że nie działa to u mnie. Wpisuje kilka liczb, potem Ctrl + Z i zamiast EOF mam wpisane w konsoli ^Z.Zatwierdzam to enterem i nie mogę już nic wpisywać dalej do programu. Jest fail, bo do typu int próbuje wpisać coś innego. Może jak wejdę na Debiana to będzie inaczej, bo na co dzień używam Visual Studio na Windowsie.

komentarz 14 kwietnia 2017 przez mokrowski Mędrzec (156,260 p.)

No to jak Ci nie działa z cmd (nie będę wnikał z jakiego powodu), to "karm program" z pliku. W argumentach uruchomienia podaj:

program.exe < plik_z_danymi.txt

Będziesz miał z automatu wklepywane dane i zakończenie poprawne strumienia. 

Podobne pytania

–1 głos
0 odpowiedzi 190 wizyt
pytanie zadane 10 lutego 2020 w C i C++ przez Nabuchadonozor Gaduła (3,120 p.)
+1 głos
2 odpowiedzi 574 wizyt
pytanie zadane 12 czerwca 2019 w C i C++ przez k222 Nałogowiec (30,150 p.)
0 głosów
0 odpowiedzi 137 wizyt
pytanie zadane 28 kwietnia 2019 w C i C++ przez BinaryMan Stary wyjadacz (12,620 p.)

92,958 zapytań

141,919 odpowiedzi

321,149 komentarzy

62,290 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Wprowadzenie do ITsec, tom 2

Można już zamawiać tom 2 książki "Wprowadzenie do bezpieczeństwa IT" - będzie to około 650 stron wiedzy o ITsec (17 rozdziałów, 14 autorów, kolorowy druk).

Planowana premiera: 30.09.2024, zaś planowana wysyłka nastąpi w drugim tygodniu października 2024.

Warto preorderować, tym bardziej, iż mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy dodatkowe 15% zniżki! Dziękujemy zaprzyjaźnionej ekipie Sekuraka za kod dla naszej Społeczności!

...