Я хочу обернуть vector<char>
с помощью std::istream
(поэтому чтение вектора будет выполняться через интерфейс istream
)
Каким образом это сделать?
Я хочу обернуть vector<char>
с помощью std::istream
(поэтому чтение вектора будет выполняться через интерфейс istream
)
Каким образом это сделать?
Вы должны определить подкласс streambuf
, обертывающий vector
, и передать экземпляр этого в конструктор istream.
Если данные не изменяются после построения, достаточно настроить указатели данных с помощью streambuf::setg()
; реализация по умолчанию для других участников делает правильную вещь:
template<typename CharT, typename TraitsT = std::char_traits<CharT> >
class vectorwrapbuf : public std::basic_streambuf<CharT, TraitsT> {
public:
vectorwrapbuf(std::vector<CharT> &vec) {
setg(vec.data(), vec.data(), vec.data() + vec.size());
}
};
std::vector<char> data;
// ...
vectorwrapbuf<char> databuf(data)
std::istream is(&databuf);
Если вам нужно что-то более продвинутое, переопределите метод streambuf::underflow
.
с использованием Boost:
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/array.hpp>
using namespace boost::iostreams;
basic_array_source<char> input_source(&my_vector[0], my_vector.size());
stream<basic_array_source<char> > input_stream(input_source);
или даже проще:
#include <boost/interprocess/streams/bufferstream.hpp>
using namespace boost::interprocess;
bufferstream input_stream(&my_vector[0], my_vector.size());
Адаптация ответа от Получите istream от char * и предположим, что это то, что вы пытаетесь сделать:
// Forward declarations
std::vector<char> my_create_buffer();
void my_consume_buffer( std::istream & is );
// What you want to be able to write
std::vector<char> buffer = my_create_buffer();
my_consume_buffer( wrap_vector_as_istream(buffer) );
Затем вы можете создать wrap_vector_as_istream
следующим образом (непроверенный):
#include <iostream>
#include <istream>
#include <streambuf>
#include <string>
struct wrap_vector_as_istream : std::streambuf
{
wrap_vector_as_istream(std::vector<char> & vec ) {
this->setg(&vec[0], &vec[0], &vec[0]+vec.size() );
}
};
Одна вещь, о которой нужно знать. Созданный объект содержит указатели на память векторов. Поэтому, если вы добавляете или удаляете значения в вектор, имея вокруг этого обертки, вы направляетесь к сбою.
(О, и если вы меня проголосуете, пожалуйста, голосуйте за сообщение, которое я адаптировал.)
Вам бы удалось просто создать класс, который реализует оператор → как поток, что-то вроде этого:
template<class _ITy>
class RangeStreamLite
{
private:
_ITy Begin;
_ITy End;
_ITy Next;
public:
RangeStreamLite(_ITy begin, _ITy end) :
Begin(begin),
End(end),
Next(begin)
{
// Do nothing.
}
template<class _OTy>
RangeStreamLite& operator>>(_OTy& out)
{
out = *Next;
++Next;
return *this;
}
void reset()
{
Next = Begin;
}
};
Это "быстрое и грязное" решение, "поток lite", это не поток в правильном смысле, но он работает, когда все, что вам нужно, является поверхностным потоковым устройством. Правильное создание пользовательского потока немного сложнее и потребует от вас наследования из std:: streambuf и реализации необходимых функций. Вот несколько ссылок, которые стоит посмотреть:
Если вам хорошо сменить ваш vector<char>
, вы можете использовать Boost Interprocess 'vectorstream
. Пример:
#include <boost/interprocess/streams/vectorstream.hpp>
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main(int argc, char **argv)
{
static const char inp[] = "123 45 666";
vector<char> v(inp, inp + sizeof inp - 1);
using ivectorstream =
boost::interprocess::basic_ivectorstream<std::vector<char>>;
ivectorstream is;
is.swap_vector(v);
while (!is.eof()) {
int i = 0;
is >> i;
cout << i << '\n';
}
is.swap_vector(v);
cout << string(v.begin(), v.end()) << '\n';
return 0;
}
В качестве альтернативы, если вы не можете или не хотите мутировать ваш vector<char>
, вы можете использовать Boost Interprocess 'bufferstream
. С bufferstream
вам не нужно менять свой вектор. Пример:
#include <boost/interprocess/streams/bufferstream.hpp>
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main(int argc, char **argv)
{
static const char inp[] = "123 45 666";
vector<char> v(inp, inp + sizeof inp - 1);
boost::interprocess::ibufferstream is(v.data(), v.size());
while (!is.eof()) {
int i = 0;
is >> i;
cout << i << '\n';
}
return 0;
}
Вам нужно будет написать настраиваемую поточную реализацию, которая наследует от istream
. Это легко сделать с помощью Boost.Iostreams
- все, что вам нужно сделать, это реализовать простой Source.