2009-08-05 31 views
9

में प्रवेश करने के लिए मुझे स्ट्रीम पर दो पुस्तकालयों को पुल करने की आवश्यकता है।std :: istream या समकक्ष

QDataStream which is a stream from Qt 

और लग रहा है कि इस

void read_something(istream& i); 

जैसे मैं कैसे QDataStream बनाई गई है पर कोई नियंत्रण नहीं है और मैं समारोह read_somthing के इंटरफेस बदलने की अनुमति नहीं कर रहा हूँ एक और पुस्तकालयों से कुछ कार्य करते हैं।

पहली बात जो मैं सोच सकता हूं वह एक वर्ग है जो आईट्रीम प्राप्त करता है और QDataStream को लपेटता है। क्या किसी ने पहले ऐसा किया है?

यदि मैंने सोचा कि उचित तरीका नहीं है, तो मुझे आश्चर्य है कि इसे प्राप्त करने का सबसे अच्छा तरीका क्या है।

+0

आप read_something का अपना स्वयं का कार्यान्वयन लिख रहे हैं, या आप इस समारोह कॉल करने के लिए कोशिश कर रहे हैं? – Ropez

उत्तर

14

आपको क्या करना चाहिए एक स्ट्रीमबफ लिखना है जो QDataStream readBytes का उपयोग करता है और इसके कार्यों को लागू करने के लिए लिखने के बाइट्स का उपयोग करता है। फिर स्ट्रीमबफ को rdbuf के साथ एक आईट्रीम में पंजीकृत करें (आप एक आईट्रीम वंश भी लिख सकते हैं जो प्रारंभ होने पर ऐसा करता है)।

बूस्ट में लाइब्रेरी है जो स्ट्रीमबफ के लेखन को सुविधाजनक बनाने के उद्देश्य से है। स्ट्रीमबफ इंटरफ़ेस को समझने के बजाय इसका उपयोग करना आसान हो सकता है (व्यक्तिगत रूप से मैंने कभी इसका उपयोग नहीं किया है, लेकिन मैंने एकाधिक स्ट्रीमबफ लिखा है; मैं देखूंगा कि मेरे पास एक उदाहरण है जिसे मैं पोस्ट कर सकता हूं)।

संपादित करें: यहां कुछ है (फ्रेंच में टिप्पणी की गई - यह fr.comp.lang.C++ के फ्रेंच एफएक्यू से आता है - मेरे पास अनुवाद के लिए कोई समय नहीं है और लगता है कि उन्हें हटाने के लिए उन्हें छोड़ना बेहतर है) जो FILE * एक स्ट्रीमबफ में कॉल लपेटता है। यह निजी विरासत के उपयोग का एक शो केस भी है: यह सुनिश्चित करना कि सदस्य बनने के लिए बेस क्लास से पहले क्या शुरू किया जा सके। आईओएसट्रीम के मामले में, बेस क्लास भी एक पूर्ण सूचक प्राप्त कर सकता है और उसके बाद सदस्य init() स्ट्रीमबफ सेट करने के लिए उपयोग किया जाता है।

#include <stdio.h> 
#include <assert.h> 

#include <iostream> 
#include <streambuf> 

// streambuf minimal encapsulant un FILE* 
// - utilise les tampons de FILE donc n'a pas de tampon interne en 
//  sortie et a un tampon interne de taille 1 en entree car l'interface 
//  de streambuf ne permet pas de faire moins; 
// - ne permet pas la mise en place d'un tampon 
// - une version plus complete devrait permettre d'acceder aux 
//  informations d'erreur plus precises de FILE* et interfacer aussi 
//  les autres possibilites de FILE* (entre autres synchroniser les 
//  sungetc/sputbackc avec la possibilite correspondante de FILE*) 

class FILEbuf: public std::streambuf 
{ 
public: 

    explicit FILEbuf(FILE* cstream); 
    // cstream doit etre non NULL. 

protected: 

    std::streambuf* setbuf(char_type* s, std::streamsize n); 

    int_type overflow(int_type c); 
    int  sync(); 

    int_type underflow(); 

private: 

    FILE* cstream_; 
    char  inputBuffer_[1]; 
}; 

FILEbuf::FILEbuf(FILE* cstream) 
    : cstream_(cstream) 
{ 
    // le constructeur de streambuf equivaut a 
    // setp(NULL, NULL); 
    // setg(NULL, NULL, NULL); 
    assert(cstream != NULL); 
} 

std::streambuf* FILEbuf::setbuf(char_type* s, std::streamsize n) 
{ 
    // ne fait rien, ce qui est autorise. Une version plus complete 
    // devrait vraissemblablement utiliser setvbuf 
    return NULL; 
} 

FILEbuf::int_type FILEbuf::overflow(int_type c) 
{ 
    if (traits_type::eq_int_type(c, traits_type::eof())) { 
    // la norme ne le demande pas exactement, mais si on nous passe eof 
    // la coutume est de faire la meme chose que sync() 
    return (sync() == 0 
     ? traits_type::not_eof(c) 
     : traits_type::eof()); 
    } else { 
    return ((fputc(c, cstream_) != EOF) 
     ? traits_type::not_eof(c) 
     : traits_type::eof()); 
    } 
} 

int FILEbuf::sync() 
{ 
    return (fflush(cstream_) == 0 
     ? 0 
     : -1); 
} 

FILEbuf::int_type FILEbuf::underflow() 
{ 
    // Assurance contre des implementations pas strictement conformes a la 
    // norme qui guaranti que le test est vrai. Cette guarantie n'existait 
    // pas dans les IOStream classiques. 
    if (gptr() == NULL || gptr() >= egptr()) { 
    int gotted = fgetc(cstream_); 
    if (gotted == EOF) { 
     return traits_type::eof(); 
    } else { 
     *inputBuffer_ = gotted; 
     setg(inputBuffer_, inputBuffer_, inputBuffer_+1); 
     return traits_type::to_int_type(*inputBuffer_); 
    } 
    } else { 
    return traits_type::to_int_type(*inputBuffer_); 
    } 
} 

// ostream minimal facilitant l'utilisation d'un FILEbuf 
// herite de maniere privee de FILEbuf, ce qui permet de s'assurer 
// qu'il est bien initialise avant std::ostream 

class oFILEstream: private FILEbuf, public std::ostream 
{ 
public: 
    explicit oFILEstream(FILE* cstream); 
}; 

oFILEstream::oFILEstream(FILE* cstream) 
    : FILEbuf(cstream), std::ostream(this) 
{ 
} 

// istream minimal facilitant l'utilisation d'un FILEbuf 
// herite de maniere privee de FILEbuf, ce qui permet de s'assurer 
// qu'il est bien initialise avant std::istream 

class iFILEstream: private FILEbuf, public std::istream 
{ 
public: 
    explicit iFILEstream(FILE* cstream); 
}; 

iFILEstream::iFILEstream(FILE* cstream) 
    : FILEbuf(cstream), std::istream(this) 
{ 
} 

// petit programme de test 
#include <assert.h> 
int main(int argc, char* argv[]) 
{ 
    FILE* ocstream = fopen("result", "w"); 
    assert (ocstream != NULL); 
    oFILEstream ocppstream(ocstream); 
    ocppstream << "Du texte"; 
    fprintf(ocstream, " melange"); 
    fclose(ocstream); 
    FILE* icstream = fopen("result", "r"); 
    assert (icstream != NULL); 
    iFILEstream icppstream(icstream); 
    std::string word1; 
    std::string word2; 
    icppstream >> word1; 
    icppstream >> word2; 
    char buf[1024]; 
    fgets(buf, 1024, icstream); 
    std::cout << "Got :" << word1 << ':' << word2 << ':' << buf << '\n'; 
} 
+0

नोट सिंक और स्रोत अवधारणाओं का उपयोग करना एक बहुत आसान विकल्प होगा। उदाहरण के लिए, एक सिंक ऑब्जेक्ट FILE * को लपेटेगा और केवल एक लेखन फ़ंक्शन को लागू करने की आवश्यकता होगी जिसके अंतर्गत फ़ाइल पॉइंटर पर फ़्राइट करने के लिए कॉल किया जाता है। सिंक को तब बूस्ट :: आईओस्ट्रीम :: स्ट्रीम में लपेटा जा सकता है जिसे तब std :: ostream की तरह माना जा सकता है। आह मैं देखता हूं कि किसी ने पहले ही इस समाधान को संकेत दिया है। –

8

बढ़ावा धारा समाधान:

namespace boost { 
    namespace iostreams { 

     class DataStreamSource 
     { 
     public: 
      typedef char char_type; 
      typedef source_tag category; 

      DataStreamSource(QDataStream *const source) : m_source(source){ 
      } 
      std::streamsize read(char* buffer, std::streamsize n) { 
       return m_source ? m_source->readRawData(buffer, n) : -1; 
      } 

     private: 
      QDataStream *const m_source; 
     }; 
    } 
} 

// using DataStreamSource 
namespace io = boost::iostreams; 
QFile fl("temp.bin"); 
fl.open(QIODevice::ReadOnly); 
QDataStream s(&fl); 
io::stream<io::DataStreamSource> dataStream(&s); 
read_something(dataStream); 
+0

यह एक आकर्षण की तरह काम करता है – lyxera

+0

धन्यवाद बहुत बहुत धन्यवाद! – lyxera

+0

@lyxera मैंने एक सिंक - स्रोत - डिवाइस QIODevice पुल भी बनाया है: stackoverflow.com/questions/848269/mixing-qt-with-stl-and-boost-are-there-any-bridges-to-make-it आराम से/856,812 # 856,812 – TimW

संबंधित मुद्दे