Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is there no overload for printing `std::byte`?

The following code does not compile in C++20

#include <iostream>
#include <cstddef>

int main(){ 
    std::byte b {65};
    std::cout<<"byte: "<<b<<'\n';// Missing overload
}

When std::byte was added in C++17, why was there no corresponding operator<< overloading for printing it? I can maybe understand the choice of not printing containers, but why not std::byte? It tries to act as primitive type and we even have overloads for std::string, the recent std::string_view, and perhaps the most related std::complex, and std::bitset itself can be printed.

There are also std::hex and similar modifiers, so printing 0-255 by default should not be an issue.

Was this just oversight? What about operator>>, std::bitset has it and it is not trivial at all.

EDIT: Found out even std::bitset can be printed.

like image 659
Quimby Avatar asked Aug 31 '21 07:08

Quimby


2 Answers

From the paper on std::byte (P0298R3): (emphasis mine)

Design Decisions

std::byte is not an integer and not a character

The key motivation here is to make byte a distinct type – to improve program safety by leveraging the type system. This leads to the design that std::byte is not an integer type, nor a character type. It is a distinct type for accessing the bits that ultimately make up object storage.

As such, it is not required to be implicitly convertible/interpreted to be either a char or any integral type whatsoever and hence cannot be printed using std::cout unless explicitly cast to the required type.

Furthermore, this question might help.

like image 102
Ruks Avatar answered Oct 23 '22 05:10

Ruks


std::byte is intended for accessing raw data. To allow me to replace that damn uint8_t sprinkled all over the codebase with something that actually says "this is raw and unparsed", instead of something that could be misunderstood as a C string.

To underline: std::byte doesn't "try to be a primitive", it represents something even less - raw data.

That it's implemented like this is mostly a quirk of C++ and compiler implementations (layout rules for "primitive" types are much simpler than for a struct or a class).

This kind of thing is mostly found in low level code where, honestly, printing shouldn't be used. Isn't possible sometimes.

My use case, for example, is receiving raw bytes over I2C (or RS485) and parsing them into frame which is then put into a struct. Why would I want to serialize raw bytes over actual data? Data I will have access to almost immediately?

To sum up this somewhat ranty answer, providing operator overloads for std::byte to work with iostream goes against the intent of this type.

And expressing intent in code as much as possible is one of important principles in modern programming.

like image 39
Jan Dorniak Avatar answered Oct 23 '22 05:10

Jan Dorniak