web-dev-qa-db-fra.com

Comment utiliser le nouveau type std :: byte dans les endroits où un caractère non signé à l'ancienne est nécessaire?

std::byte est un nouveau type en C++ 17 qui est fait comme enum class byte : unsigned char. Cela rend impossible son utilisation sans conversion appropriée. Donc, j'ai fait un alias pour le vecteur de ce type pour représenter un tableau d'octets:

using Bytes = std::vector<std::byte>;

Cependant, il est impossible de l'utiliser à l'ancienne: les fonctions qui l'acceptent comme paramètre échouent car ce type ne peut pas être facilement converti en ancien std::vector<unsigned char> saisissez, par exemple, une utilisation de la bibliothèque zipper:

/resourcecache/pakfile.cpp: In member function 'utils::Bytes resourcecache::PakFile::readFile(const string&)':
/resourcecache/pakfile.cpp:48:52: error: no matching function for call to 'zipper::Unzipper::extractEntryToMemory(const string&, utils::Bytes&)'
     unzipper_->extractEntryToMemory(fileName, bytes);
                                                    ^
In file included from /resourcecache/pakfile.hpp:13:0,
                 from /resourcecache/pakfile.cpp:1:
/projects/linux/../../thirdparty/zipper/zipper/unzipper.h:31:10: note: candidate: bool zipper::Unzipper::extractEntryToMemory(const string&, std::vector<unsigned char>&)
     bool extractEntryToMemory(const std::string& name, std::vector<unsigned char>& vec);
          ^~~~~~~~~~~~~~~~~~~~
/projects/linux/../../thirdparty/zipper/zipper/unzipper.h:31:10: note:   no known conversion for argument 2 from 'utils::Bytes {aka std::vector<std::byte>}' to 'std::vector<unsigned char>&'

J'ai essayé d'effectuer des castings naïfs mais cela n'aide pas non plus. Donc, s'il est conçu pour être utile, sera-t-il réellement utile dans des contextes anciens? La seule méthode que je vois est d'utiliser std::transform pour utiliser un nouveau vecteur d'octets à ces endroits:

utils::Bytes bytes;
std::vector<unsigned char> rawBytes;
unzipper_->extractEntryToMemory(fileName, rawBytes);
std::transform(rawBytes.cbegin(),
               rawBytes.cend(),
               std::back_inserter(bytes),
               [](const unsigned char c) {
                   return static_cast<std::byte>(c);
               });
return bytes;

Lequel est:

  1. Laid.
  2. Prend beaucoup de lignes inutiles (peut être réécrit mais doit encore être écrit avant :)).
  3. Copie la mémoire au lieu d'utiliser simplement le morceau déjà créé de rawBytes.

Alors, comment l'utiliser dans des endroits anciens?

28
Victor Polevoy

Si votre code à l'ancienne prend des plages ou des itérateurs comme arguments, vous pouvez continuer à les utiliser. Dans les quelques cas où vous ne pouvez pas (comme les constructeurs basés sur la plage explicit), vous pouvez en théorie écrire une nouvelle classe d'itérateur qui enveloppe un itérateur dans unsigned char et convertit *it à std::byte&.

0
Davislor

Si vous voulez quelque chose qui se comporte comme un octet comme vous vous y attendez probablement mais qui est nommé différemment de char non signé, utilisez uint8_t de stdint.h. Pour presque toutes les implémentations, ce sera probablement un

typedef unsigned char uint8_t;

et encore un personnage non signé sous le capot - mais qui s'en soucie? Vous voulez juste souligner "Ce n'est pas un type de caractère". Vous n'avez tout simplement pas à vous attendre à pouvoir avoir deux surcharges de certaines fonctions, une pour char non signé et une pour uint8_t. Mais si vous le faites, le compilateur vous poussera quand même dessus ...

0
Don Pedro