2017-06-23 2 views
0

Y a-t-il un moyen d'ajouter du tampon à la fonction cin afin que je puisse utiliser efficacement tellg et seekg sur cet istream? (Je n'ai besoin de revenir qu'environ 6 caractères.) Ou y a-t-il un moyen d'encapsuler le flux avec un objet istream (peut-être personnalisé) qui agit comme un canal tampon qui me permet d'utiliser tellg/seekg pour rétablir la position du flux quelques caractères? Il pourrait ressembler à ceci:D'une certaine façon pour mettre en tampon ou envelopper cin afin que je puisse utiliser tellg/seekg?

BufferedIStream bis(cin); 
streampos pos = bis.tellg(); 
MyObjectType t = getObjectType(bis); 
bis.seekg(pos); 

En tant que travail autour, je suis en train de lire cin à EOF dans une chaîne, et le transfert de cette chaîne à un istringstream, mais cela a de nombreux côté affects négatifs que je J'aime éviter. La seule autre chose que je peux penser à faire est de surcharger toutes mes fonctions de scan/lecture sur toutes mes classes de données avec une version privée (seulement utilisée en usine) où l'en-tête est supposé avoir déjà été consommé, donc que je peux éliminer le besoin de tellg/seekg tout à fait. Cela fonctionnerait bien, mais introduirait une bonne quantité de laideur. En comparaison, tellg/seekg est isolé à mon usine et est juste deux lignes de code. Je déteste le jeter.

+1

Je recommanderais * La bibliothèque standard C++ * de Nicolai Josuttis. Ayant écrit la section pertinente du chapitre sur IOStreams, je peux être partial, cependant. La seule autre alternative que je connaisse est la bibliothèque * IOStreams and Locales * d'Angelika Langer & Klaus Kreft. Les * IOStreams * de Steve Teale sont plutôt périmés (j'ai aussi appris les bases). –

Répondre

2

Vous pouvez créer un tampon de flux de filtrage, c'est-à-dire une classe dérivée de std::streambuf. Pour prendre en charge la lecture mise en mémoire tampon, vous devez remplacer underflow() pour remplir le prochain tampon de caractère une fois les caractères saisis. Pour soutenir une recherche limitée, le tampon précédent ne serait pas rejeté mais plutôt retenu en partie. En outre, vous devez remplacer seekoff().

Quelque chose comme ça devrait faire l'affaire:

#include <iostream> 
#include <streambuf> 
#include <string> 
#include <cstdlib> 
#include <cstring> 

class bufferbuf 
    : public std::streambuf { 
    enum { size = 2000, half = size/2 }; 
    char   buffer[size]; 
    std::streambuf* sbuf; 
    std::streamoff base; 
public: 
    bufferbuf(std::streambuf* sbuf): sbuf(sbuf), base() { 
     auto read = sbuf->sgetn(this->buffer, size); 
     this->setg(this->buffer, this->buffer, this->buffer + read); 
    } 
    int underflow() { 
     if (this->gptr() == this->buffer + size) { 
      std::memmove(this->eback(), this->eback() + half, half); 
      base += half; 
      auto read = sbuf->sgetn(this->eback() + half, half); 
      this->setg(this->eback(), this->eback() + half, this->eback() + half + read); 
     } 
     return this->gptr() != this->egptr() 
      ? traits_type::to_int_type(*this->gptr()) 
      : traits_type::eof(); 
    } 
    std::streampos seekoff(off_type    offset, 
          std::ios_base::seekdir whence, 
          std::ios_base::openmode which) override { 
     if (this->gptr() - this->eback() < -offset 
      || this->egptr() - this->gptr() < offset 
      || whence != std::ios_base::cur 
      || !(which & std::ios_base::in)) { 
      return pos_type(off_type(-1)); 
     } 
     this->gbump(offset); 
     return pos_type(this->base + (this->gptr() - this->eback())); 
    } 
    std::streampos seekpos(pos_type pos, std::ios_base::openmode which) override { 
     if (off_type(pos) < this->base 
      || this->base + (this->egptr() - this->eback()) < off_type(pos) 
      || !(which & std::ios_base::in)) { 
      return pos_type(off_type(-1)); 
     } 
     this->setg(this->eback(), this->eback() + (off_type(pos) - this->base), this->egptr()); 
     return pos_type(base + (this->gptr() - this->eback())); 
    } 
}; 

int main() { 
    bufferbuf buf(std::cin.rdbuf()); 
    std::istream in(&buf); 
    // ... 
    std::string s0, s1; 
    bool relative(false); 
    if (relative) { 
     while (in >> s0 
       && (in.seekg(-int(s0.size()), std::ios_base::cur), in >> s1)) { 
      std::cout << "read " 
         << "s0='" << s0 << "' " << "s1='" << s1 << "'\n"; 
     } 
    } 
    else { 
     for (std::streampos pos = in.tellg(); 
      in >> s0 && (in.seekg(pos), in >> s1); pos = in.tellg()) { 
      std::cout << "read " 
         << "s0='" << s0 << "' " << "s1='" << s1 << "'\n"; 
     } 
    } 
} 

Le code ci-dessus fonctionne avec un couple de cas de tests simples. Il démontre les utilisations du positionnement relatif et absolu. Génériquement, je trouve inutile de chercher dans les flux car généralement tout lexique intéressant peut être fait avec un seul caractère anticipé. En conséquence, j'ai peut-être manqué quelque chose dans le contexte de la position. Cependant, je m'attends à ce que le code ci-dessus fonctionne correctement.

+0

@MatthewBusche: pour les débutants, vous pourriez vouloir expliquer ce qui ne fonctionne pas réellement et ce que vous avez essayé [plutôt que de se plaindre que vous avez downvoted]. Mis à part la petite faute de frappe pour le membre 'std :: streambuf * sbuf;', le code fonctionne réellement comme prévu (étant donné qu'il a été tapé sur un iphone qui n'est pas si mauvais). Il ne prend clairement pas en charge le positionnement absolu, bien que, par exemple, vous deviez implémenter un positionnement absolu (en remplaçant 'seekpos()' et en conservant probablement une position globale) ou vous devez revenir en arrière en utilisant le positionnement relatif. –

+0

@MatthewBusche: quelle version de mon code avez-vous testée? J'ai mis à jour le code aujourd'hui et je pense qu'il devrait fonctionner avec votre code. –

+0

Buffer fonctionne très bien maintenant. J'ai supprimé tous les articles faisant référence à l'ancienne version, car ils ne sont pas pertinents pour les futurs lecteurs. Merci beaucoup pour votre aide. Je vais vérifier le livre! –