Loading...
genadi1980 avatar genadi1980 1 Точки

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;
        }
    }

};

Тагове:
0
C++ Advanced
pavlinapppp avatar pavlinapppp 17 Точки
Best Answer

В конструктора на класа трябва да има два аргумента (вижда се от този ред Parser<int> p(std::cin, stopLine); ) значи трябва да добавим към класа и една променлива от тип стринг. Това ще е стринга-разделител, който ще се инициализира с конструктура. Аз лично съм използвала и още една променлива от тип Т, която ми съдържа текущия елемент. Използвам я във функцията на класа bool readNext(T &n) , като й въвеждам стойност от конзолата, прекарвам тази стойност през ostringstream, за да преодолея проблема с Song класа и да направя стойността на една песен само от един стринг(така мога да я сравнявам със стринга разделител)

Дано да съм помогнала

1
genadi1980 avatar genadi1980 1 Точки

Благодаря, подкарах го с int. Сега ще го мисля как да стане с <Т>.

0
genadi1980 avatar genadi1980 1 Точки

Колеги успях да подкарам нещата да вървят със 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

Може ли малко помощ пак.

0
kolioi avatar kolioi 641 Точки

Първата грешка на 19 ред е защото сравняваш n, чийто тип е T, със stopLine което е string - т.е. различни типове. За втората грешка на 17 ред виж как се използва конструктора на ostring stream. Всъщност колежката се е объркала малко, трябва ти istringstream :)

1
pavlinapppp avatar pavlinapppp 17 Точки

Не съм гледала кода който е качил колегата, малко е късно вече, но сигурно имаме различни идеи, защото аз използвам точно ostringstream:

 bool readNext(T &n){
            if (std::cin>> currEl) {
                std::ostringstream out;
                out<<currEl;
                if (out.str()!=el) {......

               }

.....

 }

0
ditchev avatar ditchev 36 Точки

Ами не, май не е нещо съвсем просто. Няколко неща са. Според мен, де!

Основното е, че съдържанието на ред 18:  line >> n; ми идва много рано. С този експрешън пълниш референцията, която връщаш към Мейн-а и не е логично да правиш допълнителни проверки, след като я напълниш. Ако всичко е наред - след нея следва само: ретърн тру и екшън :)

Аз лично първо вкарвам с std::getline съдържанието на реда от конзолата в един временен стринг. Проверявам го за ==stopLine, /забележи: не ти трябва да оверлоудваш ==, сравняваш стринг със стринг/

ако да: ретърн фолс

ако не: прекарвам временния стринг през един временен std::stringstream /за да не го мисля in- или out-/ използвайки овърлоуднатите >> и << оператори за Сонг-а. За другите типове >> и << си вървят така или иначе. И както казах: ретърн тру и екшън :)

Признавам, доста време гледах кода на колежката, докато осъзная, какво не вдявам :))

Проблема тук е пак твърде ранното вкарване на реда от конзолата в променлива от тип Т, конкретно: std::cin>> currEl

Предполагам, някъде по-нагоре има: Т currEl;

Засечката я виждам, когато Т е интеджер, а stopLine-a е стринг от няколко знака, примерно "..."

По условие това е възможно, макар че точно в условието при примера с int-овете е даден stopLine от тип int.

Вероятно и в Джъджа няма такава конкретна проверка: редица от инт-ове да се спре със стопЛайн от тип стринг.

Моля да не се приема като заяждане, просто си се поставих на мястото на процесор, на който не му се спи по това време на денонощието:))

1
pavlinapppp avatar pavlinapppp 17 Точки

Добро утро, Колега!

Само да знаете, нямам проблеми с 

i

....

1

2

....

няма нужда да проверявам преди да пълня в currEl. Да , той ми е от тип Т, но стринга го запазвам в мембър el  от тип стринг, който пълня още при инициализацията на обекта с конструктура.

Parser(std::istream& in, std::string stopLine)
        :el(stopLine) {}

За да не е като заяждане, кажете ми случай, в който смятате, че програмата ми ще гръмне. Горепоказания не е такъв.

хубав ден

0
kolioi avatar kolioi 641 Точки

Извинявам се на колежката 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, а разделителя е стринг. Сутринта нямах време да прочета внимателно коментара му. Обаче ако четем ред по ред и парсваме само валидните данни, всичко е ОК.

1
25/02/2019 23:32:38
ditchev avatar ditchev 36 Точки

Е, знаех си аз, че не трябва да се занимавам с несвойствени ми неща, а по-добре да продължа да броя овцете :))

Щом като, както казваш, кода работи и не гърми, значи е пушка :) 

Хубав ден!

0
ditchev avatar ditchev 36 Точки

Според мен, това би трябвало да гръмне (runtime!):

i

000

1

2

3

000

4

5

...

както и това:

i

5+5

1

2

3

5+5

4

5

...

 

1
pavlinapppp avatar pavlinapppp 17 Точки

Добре, прав си. Може би така е по-добре:

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 всичко си мина ОК

... или пак не е добре? :)

0
peter.gaydeek avatar peter.gaydeek 2 Точки

Колеги какво да правя със това #include "Parser.h" ??? Направих си нов хедър  за #include "PrintUtils.h" , и всичко направих но ми излизат купища грешки от Parser.h ?!? Като например : Error    C3646    'm_cCurToken': unknown override specifier   ....все нещо странно ще ми осере кода...уж всичко вървеше перфектно..

 

 

 

Извинявам се поптавка...просто Visual Studio е разпознавал Parser.h като някакъв друг хедър...а е трябвало просто да направя 2 хедъра в който единия е класа ми Parser а другия Print ! 
Готово всичко е наред 100/100 : )
 

0
25/02/2019 19:01:41
ditchev avatar ditchev 36 Точки

Сега вече е истинска пушка: манлихер :))

Дано сме полезни и на колегите с нашата дискусия.

И впрочем, в някакъв нелеп опит за оправдание, да кажа, че вчера наистина доста време се пулих в тази тема, така че видях твоите поздравления в другата тема чак след като пуснах моя пост. Получи се малко криво, за което съжалявам.

0
ditchev avatar ditchev 36 Точки

Пусни кода, де!

Как да разберем така кое трещи?

0
peter.gaydeek avatar peter.gaydeek 2 Точки

Аз добавих корекция към коментара! Оправих се...просто тук от четене на коментарите и се вдъхнових и реших да пробвам нещо и то взе че стана :D Мерси все пак! Пишете повече по форума, че от скоро взех да съм активен и ми харесва : )

0
pesosz avatar pesosz 4 Точки

Можеш ли да ми обясниш във проверката, която си качила:

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

0
25/02/2019 19:50:42
pavlinapppp avatar pavlinapppp 17 Точки

Предполагам имаш предвид коментарите за овърлоуднатите >> и << оператори за Сонг-а.Те са си дадени в ParserMain.cpp  на готово.

0
Можем ли да използваме бисквитки?
Ние използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Можете да се съгласите с всички или част от тях.
Назад
Функционални
Използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Използваме „сесийни“ бисквитки, за да Ви идентифицираме временно. Те се пазят само по време на активната употреба на услугите ни. След излизане от приложението, затваряне на браузъра или мобилното устройство, данните се трият. Използваме бисквитки, за да предоставим опцията „Запомни Ме“, която Ви позволява да използвате нашите услуги без да предоставяте потребителско име и парола. Допълнително е възможно да използваме бисквитки за да съхраняваме различни малки настройки, като избор на езика, позиции на менюта и персонализирано съдържание. Използваме бисквитки и за измерване на маркетинговите ни усилия.
Рекламни
Използваме бисквитки, за да измерваме маркетинг ефективността ни, броене на посещения, както и за проследяването дали дадено електронно писмо е било отворено.