J'ai écrit une version binaire de iostreams. Il vous permet essentiellement d'écrire des fichiers binaires, mais vous donne beaucoup de contrôle sur le format du fichier. Exemple d'utilisation: écrirait mon_int comme un entier 32 bits non signé et my_string en tant que chaîne préfixée de longueur (où le préfixe est U16LE.) Pour lire le fichier de retour, vous allez basculer. les flèches. Fonctionne très bien. Cependant, j'ai frappé une bosse dans la conception et je suis toujours sur la clôture à ce sujet. Alors, le temps de demander si. (Nous faisons quelques hypothèses, telles que des octets de 8 bits, des InTS de 2s-compléments et des flotteurs IEEE pour le moment.) P> iostreams, sous la hotte, utilisez Streambufs. C'est un design fantastique - iOSTREAMS code la sérialisation d'un "code> int code>" dans le texte et laissez le streambuf sous-jacent à gérer le reste. Ainsi, vous obtenez COUT, FRESBREAMS, SINGSTREAMS, etc. Tous, les iostreams et les Streambufs sont équipés, généralement en caractères, mais parfois aussi comme wchar. Mes données, cependant, est un flux d'octets, qui est le mieux représenté par ' Mes premières tentatives devait modeler les classes basées sur 1) Pourquoi un streambuf est-il responsable de telles choses? Il semble que les conversions de code se situent sur une responsabilité de Streambuf - Streambufs devrait adopter un flux et prendre des données tampon versées. Rien de plus. Quelque chose de haut niveau que les conversions de code ressemblent à cela devrait appartenir à iOSTreams. P> Étant donné que je ne pouvais pas obtenir les streambufs modèles pour travailler avec un caractère non signé, je suis retourné à la Char et a simplement monné des données entre Char / Sans signé Char. J'ai essayé de minimiser le nombre de moulages, pour des raisons évidentes. La plupart des données se déroulent essentiellement dans une fonction de lecture () ou d'écriture (), qui invoquent ensuite le streambuf sous-jacent. (Et utilisez un casting dans le processus.) La fonction de lecture est fondamentalement: p> bonne solution, une mauvaise solution? P> Les deux premiers Les questions indiquent que plus d'informations sont nécessaires. Premièrement, des projets tels que Boost :: La sérialisation ont été examinées, mais elles existent à un niveau supérieur, en ce sens qu'ils définissent leur propre format binaire. Ceci est plus pour la lecture / l'écriture à un niveau inférieur, où il est souhaité de définir le format, ou le format est déjà défini, ou que les métadonnées en vrac ne sont pas requises ou souhaitées. P> Deuxièmement, certains ont demandé À propos du Cependant à ce moment-là, cela ne semblait pas fonctionner. J'ai eu plusieurs problèmes avec un appel de fonction ambigu. Cela était particulièrement vrai des constantes, bien que vous puissiez, comme une affiche suggérée, jeté ou simplement la déclarer comme un non signé Char code>'. P>
non signé Char code>.
std :: basique_string code> Les modèles assez bien, mais
streambuf code> ne le fait pas. J'ai rencontré plusieurs problèmes avec une classe nommée
codecvt code>, que je ne pouvais jamais obtenir de suivre le thème
non signé (code> non signé. Cela soulève deux questions: p>
Binary :: u32le code> modificateur. C'est une instanciation d'une classe qui détient l'endansité et la largeur souhaitée, actuellement peut-être signée dans le futur. Le flux contient une copie de l'instance de cette classe la dernière fois passée et utilisée en sérialisement. C'était un peu de solution de contournement, j'ai onctuellement essayé surcharger l'opérateur << Ainsi: p>
const
5 Réponses :
Si je comprends bien, les propriétés de flux que vous utilisez pour spécifier des types seraient plus appropriées pour spécifier les valeurs de l'endian-ness, de l'emballage ou d'autres "méta-données". Le traitement des types eux-mêmes devrait être fait par le compilateur. Au moins, c'est la façon dont la STL semble être conçue.
Si vous utilisez des surcharges pour séparer automatiquement les types automatiquement, vous devez spécifier le type uniquement lorsqu'il était différent du type déclaré de la variable: P>
Stream& operator<<(int8_t); Stream& operator<<(uint8_t); Stream& operator<<(int16_t); Stream& operator<<(uint16_t); etc. uint32_t x; stream << x << (uint16_t)x;
Boost :: La sérialisation réside à un niveau légèrement supérieur et ne peut pas être utilisé pour faciliter la lecture des protocoles binaires existants, par exemple, ou donner tout le contrôle à grain fin. En ce qui concerne le Codecvt, j'ai fait des coups initiaux pour écrire un NO-OP pour un caractère non signé, mais a échoué. Quant aux définitions, j'ai initialement commencé avec ce que vous aviez, mais a rencontré des problèmes d'appels de fonction ambigu et passez à la solution actuelle. Je pourrais réessayer à nouveau, comme utiliser le type serait beaucoup plus naturel.
Eh bien, ça dirait que vous savez ce que vous faites. C'est tout le retour que j'ai. Si vous souhaitez prendre une autre fissure aux problèmes de surcharge ou de codecvt, je serais donc heureux de l'examiner.
Je pense que c'est la voie à suivre. Peut-être devriez-vous essayer de travailler les erreurs "Appel de la fonction ambigu". Je ne pense pas (je n'ai pas essayé) que la conception de la surcharge est défectueuse (je peux être prouvé comme mal)
Nous devions faire quelque chose de similaire à ce que vous faites, mais nous avons suivi un autre chemin. Je suis intéressé par la manière dont vous avez défini votre interface. Une partie de ce que je ne sais pas comment vous pouvez gérer sont les manipulateurs em> vous avez défini (binaire :: u32le, binarylu16le). avec basic_streams, le manipulateur contrôle comment tous les éléments suivants seront Lire / écrit, mais dans votre cas, cela n'a probablement aucun sens, car la taille (une partie de vos informations de manipulateur) est affectée par la variable passée et sortie. p> Dans le code ci-dessus, il peut être de déterminer que la variable La taille ne semble pas appartenir (à mon avis) aux manipulateurs. p> juste comme une note latérale, dans notre cas, comme nous avions d'autres contraintes comme définition de types d'exécution des types, et nous avons fini par construire notre propre système de type méta-type pour créer des types à l'exécution (type de variante), puis nous avons fini par mettre en œuvre de / sérialisation de ces types (style de boost), donc notre Les sérialiseurs ne fonctionnent pas avec des types de base C ++, mais plutôt de la sérialisation / paires de données. p> p> i code> est de 32 bits (en supposant que INT est 32 bits) que vous souhaitez extraire du flux sérialisé de 16 bits, tandis que vous souhaitez extraire Les 32 bits complets dans
i2 code>. Après cela, l'utilisateur est obligé d'introduire des manipulateurs pour chaque autre type transmis, sinon le manipulateur a encore effet et que le court-circuit est passé et 32 bits sont lus avec un dépassement possible et de quelque manière que ce soit. l'utilisateur obtiendra probablement des résultats inattendus. P>
J'ai fait des modifications à la question de votre réponse. Vous et l'autre affiche, faites-moi maintenant de penser à mon utilisation de manipulateurs (bonne nom, dont elle avait besoin de ...). Je me sens comme s'il y avait des problèmes avec des appels de fonction ambiguës. Ceci est esp. vrai de << 6, bien que cela puisse être fait avec dans << uint16_t (6). Les manipulateurs persistent et c'est une erreur d'essayer de lire dans une variable de 16 bits avec un manipulateur 32 bits présent. Cependant, je vais penser à cette utilisation et voir si peut-être que le modèle décrit par vous deux est un meilleur ajustement.
Le nom n'est pas le mien, mais plutôt standard. Dans la norme C ++, le chapitre 27.6 est intitulé: "Mise en forme et manipulateurs", et contrairement à votre version, elles ne sont pas implémentées comme des objets passés dans le flux mais plutôt comme des fonctions libres (modèles) qui sont exécutées à l'intérieur du flux (iOS_Base ou basic_ios <>). Dans chaque cas, ils prennent et renvoient des références au type donné (base_stream <>, basic_ios <> ou ios_base)
Je n'utiliserais pas l'opérateur << comme il était trop intimement associé au texte formaté E / S. P>
Je n'utiliserais pas de surcharge d'opérateur pour cela, en réalité. Je trouverais un autre idiome. P>
Je considère son utilisation juste dans le mouvement des choses vers / depuis un ruisseau, mais je vois peut-être votre point de vue. Néanmoins, c'est juste un appel de fonction - cela pourrait aussi facilement être remplacé par .read (...) ou .write (...), mais vous finiriez ensuite avec: flux.read (x) .read (y ) .read (z) qui peut ou peut ne pas avoir de sens. Cependant, étant donné que la hiérarchie de la classe correspond à celle des iostreams, pourquoi pas l'API aussi?
La bibliothèque standard a déjà des méthodes pouvant lire et écrire des données binaires. Ce sont des méthodes, pas des surcharges de << ou >>. La raison pour laquelle je suggère de ne pas utiliser << et >> pour les E / S binaires est que les gens pensent formatés em> entrée et sortie lorsqu'ils voient ces opérateurs. Le formatage implique des choses comme des localités, une justification sur le terrain, etc. Vous ne faites rien de cela avec des E / S binaires, c'est pourquoi la bibliothèque standard fournit les méthodes de base_istribution
Vous sont i> faire la majeure partie de cela avec des E / S binaires. Les paramètres régionaux contiennent des formats de pointe ou de virgule flottante, les champs de champs sont remplacés par l'alignement. La sortie formatée binaire est similaire au texte.
Je suis d'accord avec légaliser. J'avais besoin de faire presque exactement ce que vous faites et j'ai examiné la surcharge Ma solution (qui n'a besoin que de sérialiser temporairement des données sur une seule machine et n'avait donc pas besoin d'aborder l'endansion. ) Était basé sur ce motif: p> i alors surchargé de surcharge supplémentaire read_raw / write_raw pour tout type de non-POD (par exemple des chaînes). Notez que seule la première version de READ_RAW doit être surchargée; Si vous Utilisez ADL correctement , la deuxième version (1-Arg) peut appeler Les surcharges 2-AG définies ultérieurement et dans d'autres espaces de noms. P> Ecrivez l'exemple: P> /
>> code>, mais est arrivé à la conclusion que iOSTREAM n'était tout simplement pas conçu pour l'adapter . Pour une chose, je ne voulais pas avoir à sous-classer les cours de flux pour pouvoir définir mes surcharges.
int32_t x = read_raw<int32_t>(is); // explicit form
int64_t y;
read_raw(is, y); // implicit form
int8_t z = numeric_cast<int8_t>(read_raw<int16_t>(is));
dans moderne C ++, vous pouvez utiliser << avec des données binaires à l'aide de String_View car il n'est pas terminé NULL et peut être explicitement dimensionné.
XXX PRE> P>
Votre problème d'appel de fonction ambigu peut être dû au fait que [u] int32_t est généralement défini comme un "[non signé] long". Donc, si vous essayez d'écrire un "[non signé] INT", quels littéraux numériques ont tendance à être, une promotion est nécessaire, mais le type à promouvoir est ambigu (par exemple Long VS Double).
Pouvez-vous s'il vous plaît poster votre sortie du compilateur sur ces conflits que vous avez eues avec Unsigné Char Streambuf?