【问题标题】:Making a custom istream manipulator制作自定义 istream 操纵器
【发布时间】:2016-08-16 18:48:04
【问题描述】:

我想制作一个自定义的 istream 操纵器,它从输入中读取 2 个字符,然后从输入中跳过 2 个字符,并一直这样做,直到用完任何输入为止。

例如,如果我有这样的代码:

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

其中skipchar是我的操纵器,如果用户输入1122334455str应该包含113355

这是我到目前为止所得到的,我不知道应该在 while 循环条件中放入什么才能使这段代码正常工作:

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

任何帮助将不胜感激。

【问题讨论】:

    标签: c++ io istream manipulators


    【解决方案1】:

    这是一个非常好的问题。我不知道这是否可能。但是我实现了一些不同的东西,通过重载&gt;&gt; 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;
    }
    

    【讨论】:

    • 谢谢!这段代码很简单,就是我想要的!
    【解决方案2】:

    这很棘手; istream 操纵器不作为流上的“过滤器”运行,而是作为单次操作。标准提供的 istream 操纵器(noskipwshex 等)通过设置和清除流上的标志来完成它们的工作,因此它们只公开已经可用的功能。

    但是,可以创建一个过滤streambuf,包装cin(或任何输入流)的streambuf,并使用操纵器安装或删除它:

    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
    

    【讨论】:

    • 太棒了。谢谢! Wa-a-a-y 对我来说太高级了,但我会尽可能多地搜索 iostream 的东西,以便更好地理解你的代码:)
    猜你喜欢
    • 1970-01-01
    • 2012-10-11
    • 2015-06-02
    • 2010-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-11
    • 2011-12-03
    相关资源
    最近更新 更多