如何在需要旧式无符号字符的地方使用新的 std::byte 类型?

2021-12-21 00:00:00 vector c++ c++17

std::byte 是 C++17 中的一种新类型,它被定义为 enum class byte : unsigned char.这使得在没有适当转换的情况下无法使用它.所以,我为这种类型的向量做了一个别名来表示一个字节数组:

std::byte is a new type in C++17 which is made as enum class byte : unsigned char. This makes impossible to use it without appropriate conversion. So, I have made an alias for the vector of such type to represent a byte array:

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

但是,不能在旧式中使用它:接受它作为参数的函数会失败,因为这种类型不能轻易转换成旧的 std::vector输入,例如,zipper 库的用法:

However, it is impossible to use it in old-style: the functions which accept it as a parameter fail because this type can not be easily converted to old std::vector<unsigned char> type, for example, a usage of zipper library:

/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>&'

我曾尝试执行幼稚的转换,但这也无济于事.那么,如果它被设计为有用的,它在旧的上下文中真的有用吗?我看到的唯一方法是使用 std::transform 在这些地方使用新的字节向量:

I have tried to perform naive casts but this does not help also. So, if it is designed to be useful, will it be actually useful in old contexts? The only method I see is to use std::transform for using new vector of bytes in these places:

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;

是:

  1. 丑.
  2. 占用了很多无用的行(可以重写,但仍然需要在之前编写:)).
  3. 复制内存,而不是仅仅使用已经创建的 rawBytes 块.

那么,如何在老地方使用它?

So, how to use it in old places?

推荐答案

您忽略了 std::byte 最初被发明的原因.发明它的原因是在内存中保存一个原始字节而不假设它是一个字符.您可以在 cppreference 中看到这一点.

You're missing the point why std::byte was invented in the first place. The reason it was invented is to hold a raw byte in memory without the assumption that it's a character. You can see that in cppreference.

与 char 和 unsigned char 一样,它可以用来访问被其他对象(对象表示)占用的原始内存,但与那些类型不同的是,它不是字符类型,也不是算术类型.

Like char and unsigned char, it can be used to access raw memory occupied by other objects (object representation), but unlike those types, it is not a character type and is not an arithmetic type.

请记住,出于安全考虑,C++ 是一种强类型语言(因此隐式转换在许多情况下受到限制).含义:如果从 bytechar 的隐式转换是可能的,那么它就会失败.

Remember that C++ is a strongly typed language in the interest of safety (so implicit conversions are restricted in many cases). Meaning: If an implicit conversion from byte to char was possible, it would defeat the purpose.

因此,要回答您的问题:要使用它,您必须在任何时候对其进行分配:

So, to answer your question: To use it, you have to cast it whenever you want to make an assignment to it:

std::byte x = (std::byte)10;
std::byte y = (std::byte)'a';
std::cout << (int)x << std::endl;
std::cout << (char)y << std::endl;

按照设计,其他任何事情都行不通!所以这个转换很难看,同意,但如果你想存储字符,那么使用 char.不要使用字节,除非您想存储原始内存默认情况下不应将其解释为 char.

Anything else shall not work, by design! So that transform is ugly, agreed, but if you want to store chars, then use char. Don't use bytes unless you want to store raw memory that should not be interpreted as char by default.

而且您问题的最后一部分通常是不正确的:您不必复制,因为您不必复制整个向量.如果您暂时需要将 byte 读取为 char,只需在需要将其用作 的地方 static_cast 即可字符.它不花钱,而且是类型安全的.

And also the last part of your question is generally incorrect: You don't have to make copies, because you don't have to copy the whole vector. If you temporarily need to read a byte as a char, simply static_cast it at the place where you need to use it as a char. It costs nothing, and is type-safe.

<小时>至于你在关于将 std::vector 转换为 std::vector 的评论中的问题,你不能那样做.但是您可以使用下面的原始数组.所以,下面有一个类型 (char*):


As to your question in the comment about casting std::vector<char> to std::vector<std::byte>, you can't do that. But you can use the raw array underneath. So, the following has a type (char*):

std::vector<std::byte> bytes;
// fill it...
char* charBytes = reinterpret_cast<char*>(bytes.data()); 

它的类型为 char*,它是指向数组第一个元素的指针,无需复制即可取消引用,如下所示:

This has type char*, which is a pointer to the first element of your array, and can be dereferenced without copying, as follows:

std::cout << charBytes[5] << std::endl; //6th element of the vector as char

以及您从 bytes.size() 获得的大小.这是有效的,因为 std::vector 在内存中是连续的.您通常无法使用任何其他标准容器(双端队列、列表等...)执行此操作.

And the size you get from bytes.size(). This is valid, since std::vector is contiguous in memory. You can't generally do this with any other std container (deque, list, etc...).

虽然这是有效的,但它从等式中消除了部分安全性,请记住这一点.如果你需要char,不要使用byte.

While this is valid, it removes part of the safety from the equation, keep that in mind. If you need char, don't use byte.

相关文章