Возврат надстройки streambuf из функции - PullRequest
0 голосов
/ 11 июня 2018

Я пытаюсь обернуть код, который читает файлы gz в функцию, исходный код взят из https://techoverflow.net/2013/11/03/c-iterating-lines-in-a-gz-file-using-boostiostreams/

Моя попытка

boost::iostreams::filtering_streambuf<boost::iostreams::input> func(std::string filename);
boost::iostreams::filtering_streambuf<boost::iostreams::input> func(std::string filename)
{
  std::ifstream file(filename, std::ios_base::in | std::ios_base::binary);
  boost::iostreams::filtering_streambuf<boost::iostreams::input> inbuf;
  inbuf.push(boost::iostreams::gzip_decompressor());
  inbuf.push(file);
  return inbuf;

}
void mymainfunc(std::string filename)
{

  //Convert streambuf to istream
  std::istream ifstrm( func( filename));
  std::string line;
  while(std::getline(ifstrm, line)) {
        std::cout << line << std::endl;
    }
}

Код работает нормально, если не запускаетсячерез функцию я делаю что-то не так в типе возврата, я думаю.Ошибка: https://pastebin.com/kFpjYG0M

1 Ответ

0 голосов
/ 11 июня 2018

Потоки не копируются.Фактически, этот filterstreamstreambuf даже не может быть перемещен.

Так что в этом случае вы захотите динамически размещать и возвращать с помощью смарт-указателя.Однако даже простой возврат фильтрующего streambuf не будет работать, потому что он будет содержать ссылку на ifstream.И это местный.

Итак, может быть, вам нужно упаковать его:

Live On Coliru

#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <fstream>

namespace bio = boost::iostreams;

struct MySource {
    using fisb = bio::filtering_istreambuf;

    struct State {
        State(std::string filename) : ifs(filename, std::ios::binary) {
            buf.push(bio::gzip_decompressor());
            buf.push(ifs);
        }

        fisb buf;
        std::ifstream ifs;
        std::istream is { &buf };
    };

    std::unique_ptr<State> _state;

    operator std::istream&() const { return _state->is; }
};

MySource func(std::string filename) {
    auto inbuf = std::make_unique<MySource::State>(filename);
    return {std::move(inbuf)};
}

#include <iostream>
void mymainfunc(std::string filename)
{
    auto source = func(filename);
    std::istream& is = source;

    std::string line;
    while(std::getline(is, line)) {
        std::cout << line << std::endl;
    }
}

int main(){
    mymainfunc("test.cpp.gz");
}

Альтернатива # 1

Вы можете упростить:

Live On Coliru

struct MySource {
    struct State {
        State(std::string filename) : ifs(filename, std::ios::binary) {
            is.push(bio::gzip_decompressor());
            is.push(ifs);
        }

        std::ifstream ifs;
        bio::filtering_istream is;
    };

    std::unique_ptr<State> _state;

    operator std::istream&() const { return _state->is; }
};

Отдельное использование потокового буфера делает его проще.

Альтернатива # 2

Не копирование всего объекта имеет свою элегантность:

Live On Coliru

#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <fstream>
#include <iostream>

void mymainfunc(std::istream& is) {
    std::string line;
    while(std::getline(is, line)) {
        std::cout << line << std::endl;
    }
}

namespace bio = boost::iostreams;

int main(){
    std::ifstream ifs("test.cpp.gz", std::ios::binary);

    bio::filtering_istream is;
    is.push(bio::gzip_decompressor());
    is.push(ifs);

    mymainfunc(is);
}
...