มีวิธีในการสร้าง stringstream จาก string_view โดยไม่คัดลอกข้อมูลหรือไม่


10

ฉันคิดว่านั่นเป็นคำถามที่ค่อนข้างตรงไปตรงมา ฉันต้องการใช้โดยเฉพาะstd::get_timeแต่ต้องการกระแสข้อมูลบางประเภทเพื่อใช้กับ ฉันกำลังส่งผ่านข้อมูลในstring_viewและต้องการหลีกเลี่ยงการคัดลอกเพียงเพื่อแยกวันที่


1
ฉันเห็นได้แล้วตอนนี้มาที่ C ++ 23: std::basic_string_view_stream;-) ไม่แน่ใจว่าคุณสามารถหลีกเลี่ยงการคัดลอกได้ไหม บางทีฮาเวิร์ดจะรู้เคล็ดลับ
NathanOliver

2
การเลิกใช้งานระยะยาวstd::strstreamสามารถทำได้
Igor Tandetnik

ฉันติดแท็ก C ++ 14 ผิดเพราะนั่นคือสิ่งที่เราทำในโครงการนี้ boost::string_viewที่จริงผมลืมเรากำลังใช้ คำถามนี้ยังใช้ได้อยู่
Bartek Banachewicz

คำตอบ:


5

คุณสามารถทำได้อย่างง่ายดายด้วยห้องสมุด Boost.Iostreams:

#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>

#include <iostream>
#include <string>

int main() {
    std::string_view buf{"hello\n"};
    boost::iostreams::stream<boost::iostreams::basic_array_source<char>> stream(buf.begin(), buf.size());

    std::string s;
    stream >> s;
    std::cout << s << '\n';
}

คุณควรจะทำเช่นนั้นกับstd::stringstreamและstd::basic_stringbuf<CharT,Traits,Allocator>::setbufแต่มาตรฐาน C ++ เรียบร้อยแล้วความต้องการของมัน:

ผล [ของsetbuf] คือการดำเนินการที่กำหนดไว้: การใช้งานบางอย่างทำอะไรในขณะที่การใช้งานบางล้างstd::stringสมาชิกปัจจุบันใช้เป็นกันชนและเริ่มใช้ผู้ใช้จัดแถวอักขระขนาดnซึ่งมีองค์ประกอบแรกคือการชี้ไปs, เป็นกันชนและ ลำดับอักขระอินพุต / เอาต์พุต


1

โซลูชันทางเลือกโดยไม่มี Boost.IOstream (เมื่อคุณไม่สามารถใช้งานได้) มันขึ้นอยู่กับการขยาย std :: basic_streambuf และ std :: basic_istream

#include <cstring>
#include <iostream>
#include <istream>
#include <string_view>

template<typename __char_type, class __traits_type >
class view_streambuf final: public std::basic_streambuf<__char_type, __traits_type > {
private:
    typedef std::basic_streambuf<__char_type, __traits_type > super_type;
    typedef view_streambuf<__char_type, __traits_type> self_type;
public:

    /**
    *  These are standard types.  They permit a standardized way of
    *  referring to names of (or names dependent on) the template
    *  parameters, which are specific to the implementation.
    */
    typedef typename super_type::char_type char_type;
    typedef typename super_type::traits_type traits_type;
    typedef typename traits_type::int_type int_type;
    typedef typename traits_type::pos_type pos_type;
    typedef typename traits_type::off_type off_type;

    typedef typename std::basic_string_view<char_type, traits_type> source_view;

    view_streambuf(const source_view& src) noexcept:
      super_type(),
      src_( src )
    {
        char_type *buff = const_cast<char_type*>( src_.data() );
        this->setg( buff , buff, buff + src_.length() );
    }

    virtual std::streamsize xsgetn(char_type* __s, std::streamsize __n) override
    {
        if(0 == __n)
            return 0;
        if( (this->gptr() + __n) >= this->egptr() ) {
            __n =  this->egptr() - this->gptr();
            if(0 == __n && !traits_type::not_eof( this->underflow() ) )
                return -1;
        }
        std::memmove( static_cast<void*>(__s), this->gptr(), __n);
        this->gbump( static_cast<int>(__n) );
        return __n;
    }

    virtual int_type pbackfail(int_type __c) override
    {
        char_type *pos = this->gptr() - 1;
        *pos = traits_type::to_char_type( __c );
        this->pbump(-1);
        return 1;
    }

    virtual int_type underflow() override
    {
        return traits_type::eof();
    }

    virtual std::streamsize showmanyc() override
    {
        return static_cast<std::streamsize>( this->egptr() - this->gptr() );
    }

    virtual ~view_streambuf() override
    {}
private:
    const source_view& src_;
};

template<typename _char_type>
class view_istream final:public std::basic_istream<_char_type, std::char_traits<_char_type> > {
    view_istream(const view_istream&) = delete;
    view_istream& operator=(const view_istream&) = delete;
private:
    typedef std::basic_istream<_char_type, std::char_traits<_char_type> > super_type;
    typedef view_streambuf<_char_type, std::char_traits<_char_type> > streambuf_type;
public:
    typedef _char_type  char_type;
    typedef typename super_type::int_type int_type;
    typedef typename super_type::pos_type pos_type;
    typedef typename super_type::off_type off_type;
    typedef typename super_type::traits_type traits_type;
    typedef typename streambuf_type::source_view source_view;

    view_istream(const source_view& src):
        super_type( nullptr ),
        sb_(nullptr)
    {
        sb_ = new streambuf_type(src);
        this->init( sb_ );
    }


    view_istream(view_istream&& other) noexcept:
        super_type( std::forward<view_istream>(other) ),
        sb_( std::move( other.sb_ ) )
    {}

    view_istream& operator=(view_istream&& rhs) noexcept
    {
        view_istream( std::forward<view_istream>(rhs) ).swap( *this );
        return *this;
    }

    virtual ~view_istream() override {
        delete sb_;
    }

private:
    streambuf_type *sb_;
};


int main(int argc, const char** argv)
{
    std::string_view v("ABDCD\n 123\n FAG\n 456789");

    view_istream<char> in( v );

    std::string s;
    in >> s;
    std::cout << s << std::endl;

    int i;
    in >> i;
    std::cout << i << std::endl;

    in >> s;
    std::cout << s << std::endl;

    in >> i;
    std::cout << i << std::endl;

    return 0;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.