2014-01-29 2 views
2

У меня есть std::basic_streambuf подкласс, который вызывает все выходные данные должны быть записаны в верхнем регистре, например:Реализация станд :: basic_streambuf подкласс для манипулирования ввода

class upper_streambuf : public std::streambuf 
{ 
    public: 
     upper_streambuf(std::streambuf &real) 
      : m_realBuffer(real) 
     { 
     } 

    protected: 
     virtual int overflow(int c) 
     { 
      int uc = std::toupper(c); 
      m_realBuffer.sputc(uc); 
      return uc; 
     } 

    private: 
     std::streambuf &m_realBuffer; 
}; 

Я использую его, как это, например, (который, кажется, работает OK):

upper_streambuf buf(*std::cout.rdbuf()); 
std::ostream ucout(&buf); 

ucout << "Hello, world!" << std::endl; // prints "HELLO, WORLD!" 

То, что я хочу достичь, это более или менее обратное, я хочу прочитать из потока и имеют все входные данные преобразуются в нижний регистр. У меня есть следующий:

class lower_streambuf : public std::streambuf 
{ 
    public: 
     lower_streambuf(std::streambuf &real) 
      : m_realBuffer(real) 
     { 
     } 

    protected: 
     virtual int underflow() 
     { 
      return std::tolower(m_realBuffer.sbumpc()); 
     } 

    private: 
     std::streambuf &m_realBuffer; 
}; 

Однако, когда я пытаюсь использовать это так:

lower_streambuf buf(*std::cin.rdbuf()); 
std::istream lcin(&buf); 
std::string line; 

std::getline(lcin, line); 

Результат является ошибкой сегментации. Я переопределяю или называю неправильные функции? Обратите внимание, что я немного новичок на C++. Пожалуйста, также обратите внимание, что я понимаю, что могу полностью прочитать ввод и просто преобразовать его в нижний регистр после его чтения, но это больше для учебных/академических целей, а не для чего-либо практического.

+0

Может быть, я пропускаю здесь коснуться, но почему это, что вы оба наследуют от станд :: streambuf, и содержат один в качестве переменной-члена. – Borgleader

+0

@Borgleader Это прекрасно. Это оболочка вокруг объекта streambuf. – 0x499602D2

+0

Для начала, [int underflow()] (http://en.cppreference.com/w/cpp/io/basic_streambuf/underflow) не принимает аргументов ... – Cubbi

ответ

4

underflow() имеет следующие условия, которые вы не смогли установить: к тому моменту, когда вы вернетесь из него, вам необходимо иметь зону получения в вашем streambuf, в которой хранится тот персонаж, который вы возвращаете.

односимвольный буфер достаточно:

protected: 
     virtual int underflow() 
     { 
      ch = std::tolower(m_realBuffer.sbumpc()); 
    +   setg(&ch, &ch, &ch+1); 
      return ch; 
     } 
    private: 
    +  char ch; // input buffer! 
     std::streambuf &m_realBuffer; 
}; 
+0

Я * думаю * Я понимаю ... буфер «получить» требуется, потому что некоторые операции чтения не «потребляют» символ, верно? – dreamlax

+0

@dreamlax сломанное постусловие = все может случиться. В частности, 'getline' вызывает' sbumpc' (в реализации, на которую я только что посмотрел), которая вызывает 'uflow', когда область get пуста, что вызывает' underflow', и если это не возвращает eof, это приводит к разрыву get указатель и возвращает символ, который есть. – Cubbi

Смежные вопросы