2016-08-16 9 views
2

Я хочу создать пользовательский манипулятор istream, который считывает 2 символа с ввода, затем пропускает 2 символа с входа и делает это до тех пор, пока не закончится какой-либо вход.Создание настраиваемого манипулятора istream

Например, если у меня есть такой код:

std::string str; 
std::cin >> skipchar >> str; 

Где skipchar мой манипулятор, если пользователь вводит 1122334455, str должен содержать 113355.

Это то, что у меня до сих пор, я не знаю, что я должен положить в состоянии в то время как петли, чтобы сделать этот код работать правильно:

istream& skipchar(istream& stream) 
{ 
    char c; 

    while(1) 
    { 
     for (int i = 0; i < 2; ++i) 
      stream >> c; 

     for (int i = 0; i < 2; ++i) 
      stream.ignore(1, '\0'); 
    } 

    return stream; 
} 

Любая помощь будет оценена.

ответ

2

Это очень хороший вопрос. Я не знаю, возможно ли это. Но я реализовал что-то другое, что дает вам тот же короткий синтаксис, который вы хотели, перегружая >> operator новым классом под названием Skip2. Вот код (которому мне очень понравилось писать! :-))

#include <iostream> 
#include <string> 
#include <istream> 
#include <sstream> 

using namespace std; 

class Skip2 { 
public: 
    string s; 
}; 

istream &operator>>(istream &s, Skip2 &sk) 
{ 
    string str; 
    s >> str; 

    // build new string 
    ostringstream build; 
    int count = 0; 
    for (char ch : str) { 
     // a count "trick" to make skip every other 2 chars concise 
     if (count < 2) build << ch; 
     count = (count + 1) % 4; 
    } 

    // assign the built string to the var of the >> operator 
    sk.s = build.str(); 

    // and of course, return this istream 
    return s; 
} 



int main() 
{ 
    istringstream s("1122334455"); 
    Skip2 skip; 

    s >> skip; 
    cout << skip.s << endl; 

    return 0; 
} 
+1

Спасибо! Этот код прост и делает то, что я хотел! –

2

Это сложно; istream манипуляторы не работают как «фильтры» в потоке, а скорее как операции с одним выстрелом. Исключительные манипуляторы, предоставляемые Стандартом (noskipws, hex и т. Д.), Выполняют свою работу, устанавливая и очищая флаги в потоке, поэтому они предоставляют только функциональные возможности, которые уже доступны.

Тем не менее, можно создать фильтрацию streambuf обертывание streambuf из cin (или любой входной поток) и использовать манипулятор для установки или удаления его:

struct skipbuf : std::streambuf { 
    std::unique_ptr<std::streambuf> src; 
    int i; 
    char buf[4]; 
    skipbuf(std::streambuf* src) : std::streambuf{*src}, src{src} { 
     setg(buf, buf + 2, buf + 2); 
    } 
    std::streambuf* unwrap() { 
     while (buf + i != gptr()) 
      src->sputbackc(buf[--i]); 
     return src.release(); 
    } 
    std::streambuf::int_type underflow() override { 
     setg(buf, buf, buf + std::min(i = src->sgetn(buf, 4), 2)); 
     return i ? buf[0] : traits_type::eof(); 
    } 
}; 

std::istream& skipchar(std::istream& is) { 
    is.rdbuf(new skipbuf{is.rdbuf()}); 
    return is; 
} 

std::istream& noskipchar(std::istream& is) { 
    if (auto* buf = dynamic_cast<skipbuf*>(is.rdbuf())) 
     delete (is.rdbuf(buf->unwrap()), buf); 
    return is; 
} 

Пример использования:

int main() { 
    std::istringstream iss{"1122334455 hello"}; 
    std::string s1, s2; 
    iss >> skipchar >> s1 >> noskipchar >> s2; 
    std::cout << s1 << ' ' << s2 << std::endl; 
} 

Ожидаемый результат (run it online):

113355 hello 
+0

Это потрясающе. Благодаря! Wa-a-a-y слишком продвинулся для меня, но я буду как можно больше «iostream», чтобы лучше понять ваш код :) –

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