Có cách nào để tạo một chuỗi chuỗi từ chuỗi_view mà không cần sao chép dữ liệu không?


10

Tôi nghĩ đó là một câu hỏi khá căng thẳng. Tôi đặc biệt muốn sử dụng std::get_time, nhưng nó đòi hỏi một số luồng được sử dụng. Tôi đang truyền dữ liệu trong một string_viewvà muốn tránh sao chép nó chỉ để phân tích ngày.


1
Tôi có thể thấy nó ngay bây giờ, đến với C ++ 23: std::basic_string_view_stream;-) Không chắc chắn nếu bạn có thể tránh sao chép. Có lẽ Howard sẽ biết một mánh khóe.
NathanOliver

2
Sự phản đối lâu dài std::strstreamcó thể làm điều đó.
Igor Tandetnik

Tôi đã gắn thẻ sai C ++ 14 này vì đó là những gì chúng tôi đang làm trong dự án này. Tôi thực sự quên chúng tôi đang sử dụng boost::string_view. Câu hỏi vẫn còn hiệu lực, mặc dù.
Bartek Banachewicz

Câu trả lời:


5

Bạn có thể làm điều đó một cách dễ dàng với thư viện 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';
}

Bạn sẽ có thể làm điều đó với std::stringstreamstd::basic_stringbuf<CharT,Traits,Allocator>::setbufnhưng tiêu chuẩn C ++ đã thực hiện các yêu cầu của nó:

Hiệu ứng [của setbuf] được xác định theo thực hiện: một số triển khai không làm gì cả, trong khi một số triển khai xóa std::stringthành viên hiện đang được sử dụng làm bộ đệm và bắt đầu sử dụng mảng ký tự do người dùng cung cấp n, có phần tử đầu tiên được trỏ đến s, như bộ đệm và chuỗi ký tự đầu vào / đầu ra.


1

Một giải pháp thay thế, không có Boost.IOstream (khi bạn không thể sử dụng nó). Nó dựa trên việc mở rộng std :: basic_streambuf và 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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.