Templates C++ Code Organisation: Task 3. Parser
Подхода ми към тази задача беше да закоментирам случаите type == "w" и type == "s" и да се опитам да я реша за "i". След това да опитам да я направя във вид на template, но срещам трудност в този фрагмент:
if (type == 'i') {
Parser p(std::cin, stopLine);
int n;
std::vector<int> numbers;
while (p.readNext(n)) {
numbers.push_back(n);
}
printVector(numbers);
}
Трудността идва от там, че се опитвам да подам std::cin, stopLine директно в конструктора и не знам как да го напиша, че да тръгне. Това съм измислил до сега. Моля, за помощ и идеи.
class Parser {
private:
std::istream & line;
public:
Parser(std::istream & LINE) : line(LINE) {}
bool readNext(int n) {
if (line >> n)
{
return true;
}
else
{
return false;
}
}
};
Благодаря, подкарах го с int. Сега ще го мисля как да стане с <Т>.
Колеги успях да подкарам нещата да вървят със INT и със STRING, но естествено изпитвам трудности със Song и Template
Стигнах до тук: https://pastebin.com/vUDtVzTv
Подозирам, че е нещо простичко, но все пак ми дава грешка, въпреки, че предефинирах оператора "==":
Severity Code Description Project File Line Suppression State
Error C2678 binary '==': no operator found which takes a left-hand operand of type 'T' (or there is no acceptable conversion) 03Parser c:\users\ggeorgiev20\documents\git\softuni\c++\c++ advanced\templates\03parser\printutils.h 19
Error C2064 term does not evaluate to a function taking 1 arguments 03Parser c:\users\ggeorgiev20\documents\git\softuni\c++\c++ advanced\templates\03parser\printutils.h 17
Може ли малко помощ пак.
Първата грешка на 19 ред е защото сравняваш n, чийто тип е T, със stopLine което е string - т.е. различни типове. За втората грешка на 17 ред виж как се използва конструктора на ostring stream. Всъщност колежката се е объркала малко, трябва ти istringstream :)
Не съм гледала кода който е качил колегата, малко е късно вече, но сигурно имаме различни идеи, защото аз използвам точно ostringstream:
bool readNext(T &n){
if (std::cin>> currEl) {
std::ostringstream out;
out<<currEl;
if (out.str()!=el) {......
}
.....
}
Ами не, май не е нещо съвсем просто. Няколко неща са. Според мен, де!
Основното е, че съдържанието на ред 18: line >> n; ми идва много рано. С този експрешън пълниш референцията, която връщаш към Мейн-а и не е логично да правиш допълнителни проверки, след като я напълниш. Ако всичко е наред - след нея следва само: ретърн тру и екшън :)
Аз лично първо вкарвам с std::getline съдържанието на реда от конзолата в един временен стринг. Проверявам го за ==stopLine, /забележи: не ти трябва да оверлоудваш ==, сравняваш стринг със стринг/
ако да: ретърн фолс
ако не: прекарвам временния стринг през един временен std::stringstream /за да не го мисля in- или out-/ използвайки овърлоуднатите >> и << оператори за Сонг-а. За другите типове >> и << си вървят така или иначе. И както казах: ретърн тру и екшън :)
Признавам, доста време гледах кода на колежката, докато осъзная, какво не вдявам :))
Проблема тук е пак твърде ранното вкарване на реда от конзолата в променлива от тип Т, конкретно: std::cin>> currEl
Предполагам, някъде по-нагоре има: Т currEl;
Засечката я виждам, когато Т е интеджер, а stopLine-a е стринг от няколко знака, примерно "..."
По условие това е възможно, макар че точно в условието при примера с int-овете е даден stopLine от тип int.
Вероятно и в Джъджа няма такава конкретна проверка: редица от инт-ове да се спре със стопЛайн от тип стринг.
Моля да не се приема като заяждане, просто си се поставих на мястото на процесор, на който не му се спи по това време на денонощието:))
Добро утро, Колега!
Само да знаете, нямам проблеми с
i
....
1
2
....
няма нужда да проверявам преди да пълня в currEl. Да , той ми е от тип Т, но стринга го запазвам в мембър el от тип стринг, който пълня още при инициализацията на обекта с конструктура.
Parser(std::istream& in, std::string stopLine)
:el(stopLine) {}
За да не е като заяждане, кажете ми случай, в който смятате, че програмата ми ще гръмне. Горепоказания не е такъв.
хубав ден
Извинявам се на колежката pavlinapppp че не разбрах добре от първия коментар как използва ostringstream. Ето накратко как работи:
1. Извлича поредния елемент от входния поток (extraction operator >> е дефиниран и за трите използвани типа int, string и Song). Една забележка само - вместо std::cin използвай входния поток in, който получаваш в конструктора.
2. Този елемент го "стрингосва" - преобразува го в стринг чрез ostringstream и сравнява така получения стринг със stopLine. След което връща резултата от сравнението true или false.
Метода на колегата ditchev (който използвам и аз) е следния:
1. Прочитаме целия ред като стринг.
2. Сравняваме го със stopLine и ако съвпадат връщаме false.
3. Използваме stringstream (колегата) или istringstream (аз) за да извлечем елемента, след което връщаме true.
Според мен това е по-естествения ред на операциите, но метода на колежката pavlinapppp също ще работи без проблем.
EDIT: Колегата ditchev е прав - програмата не работи коректно ако входните данни са int или Song, а разделителя е стринг. Сутринта нямах време да прочета внимателно коментара му. Обаче ако четем ред по ред и парсваме само валидните данни, всичко е ОК.
Е, знаех си аз, че не трябва да се занимавам с несвойствени ми неща, а по-добре да продължа да броя овцете :))
Щом като, както казваш, кода работи и не гърми, значи е пушка :)
Хубав ден!
Според мен, това би трябвало да гръмне (runtime!):
i
000
1
2
3
000
4
5
...
както и това:
i
5+5
1
2
3
5+5
4
5
...
Добре, прав си. Може би така е по-добре:
bool readNext(T &n){
std::string opit;
std::getline(in,opit);
std::istringstream inOpit(opit);
if ( (inOpit>>n) && (opit!=stopLine) ) {
return true;
}else {
return false;
}
}
Просто задачата не ме е предизвикала да мисля за тези изключения, защото в judge всичко си мина ОК
... или пак не е добре? :)
Колеги какво да правя със това #include "Parser.h" ??? Направих си нов хедър за #include "PrintUtils.h" , и всичко направих но ми излизат купища грешки от Parser.h ?!? Като например : Error C3646 'm_cCurToken': unknown override specifier ....все нещо странно ще ми осере кода...уж всичко вървеше перфектно..
Извинявам се поптавка...просто Visual Studio е разпознавал Parser.h като някакъв друг хедър...а е трябвало просто да направя 2 хедъра в който единия е класа ми Parser а другия Print !
Готово всичко е наред 100/100 : )
Сега вече е истинска пушка: манлихер :))
Дано сме полезни и на колегите с нашата дискусия.
И впрочем, в някакъв нелеп опит за оправдание, да кажа, че вчера наистина доста време се пулих в тази тема, така че видях твоите поздравления в другата тема чак след като пуснах моя пост. Получи се малко криво, за което съжалявам.
Пусни кода, де!
Как да разберем така кое трещи?
Аз добавих корекция към коментара! Оправих се...просто тук от четене на коментарите и се вдъхнових и реших да пробвам нещо и то взе че стана :D Мерси все пак! Пишете повече по форума, че от скоро взех да съм активен и ми харесва : )
Можеш ли да ми обясниш във проверката, която си качила:
template <class T>
bool Parser<T>::readNext(T &n)
{
std::string opit;
std::getline(std::cin,opit);
std::istringstream inOpit(opit);
if ( (inOpit >> n) && (opit != this->stopLine) )
{
return true;
}
else
{
return false;
}
}
Това InOpit >> n , какво точно прави? Значи, до колкото разбрах след като сме подали stopLine, влизаме в тази булева функция, и седим там, докато не срещнем същия stopLine, но до колкото знам операторът >> се използва за наливане на информация в нещо. Не съм Override-вал никой оператор в моята програма
Ето ми го кода от Parser.h:
#ifndef PARSER_H
#include <iostream>
#include <vector>
#include <sstream>
template<class T>
class Parser {
private:
std::istream & line;
std::string stopLine;
public:
Parser(std::istream & LINE, std::string stopLine) : line(LINE) , stopLine(stopLine) {}
bool readNext(T &elem);
};
template <class T>
bool Parser<T>::readNext(T &n)
{
std::string opit;
std::getline(std::cin,opit);
std::istringstream inOpit(opit);
if ( (inOpit >> n) && (opit != this->stopLine) )
{
return true;
}
else
{
return false;
}
}
#define PARSER_H
#endif // !PARSER_H
работата е там, че като принтирам нещо ми излиза на един ред всичко, не знам как да променя това, което е качено тук, така че да добавя space. другото което ме притеснява е че говорихте за някакъв overload, а аз никъде не съм ползвал такова нещо и програмата си ми върви
П.С. Бях забравил че има още 1 файл, който отговаря за принтирането. :D съжалявам за тъпия коментар, но все още остава въпроса за това което трябва да over-ride-nem
Предполагам имаш предвид коментарите за овърлоуднатите >> и << оператори за Сонг-а.Те са си дадени в ParserMain.cpp на готово.