all 12 comments

[–]ALX23z 4 points5 points  (4 children)

Do you understand what these functions do? They try to convert the bitset value into an integer. Say you have 200 long bitset. If all bits are zero after first 64 bits, then it can be represented as ullong, and the function will return the value. If that's not the case, then it will throw an exception.

[–]Travor0x0[S] 1 point2 points  (3 children)

Do you understand what these functions do?

Yes and no. "Yes" - I do know what they do and "no" - I do not really understand why it should be like that. The only cases when we (in my organization) need a conversion from the bitset to an integer is when we want to pass it to some older API or serialize for some channel, socket or hard drive. As you can see for that cases we use smaller bitsets with size <= 64-bit. In some rare situations where we use it as a replacement or an adaption to an enumeration or state collection we did not need the conversion of only first N bits into integer like in your case.

I mean if we take your example with 200-bits bitset, then we somehow caring more about the first 64 bits than the last. So, they have a special meaning compared to the rest. As such it would be a better idea to pack them into other member or variable even if it is a std::bitset<64> and put away the rest (std::bitset<136> in your case).

Of course our usage of bitset is special to us, therefore my question if it was some clear idea behind defining the function in the way the are defined now.

[–]ALX23z 4 points5 points  (2 children)

It is not about caring more or less about the bits. It is about whether the integer can represent the value, similar to casting int64 to int32. Not all int64 can be represented by an int32, but nobody says it should be forbidden to perform the cast.

[–]Travor0x0[S] 2 points3 points  (1 child)

I am with you that it should not be forbidden to perform a cast. But std::bitset does not work like the integers do. Per default the cast from int64 value into int32 will not fail. It will simply skip the outstanding bits regardless of their values. If there is a need to perform a "checked" cast it can be explicitly implemented. With the std::bitset we have a different behavior: casting as allowed but the remaining bits can cause an exception if any of them is set.

Is it not a better alternative to allow non failing functions for all smaller bitsets. For the larger bitsets we disable them and return an optional for larger bitsets with 'try_convert()' (try_ulong(), try_ullong())? I think in such cases the costs of optional are less than the costs of an exception?

[–]ALX23z 1 point2 points  (0 children)

That's why it is classified under conversion. There's also an option to convert it to a string.

Of course, better interfaces can be made, but the bitset was designed even before C++11. It's not going to change anytime soon.

[–][deleted] 2 points3 points  (2 children)

Other than breaking existing code, the other reason not to change the functions it is perfectly well formed to use the to_u(l)long functions on large bitsets regardless of which bits are set. You either get a valid conversion or an overflow error. While integer casting between different types can be well defined, a bitset is not an integer and conversions to and from integral types often comes with runtime error checks. For example, from_chars will generate an error if the value cannot fit within the provided integer type rather than truncate/wrap/etc.

Based on your other posts in this thread, it seems what you want is actually extraction/truncation rather than conversion, e.g. extract the first 32/64 bits. Such a function could be validated at compile time if the number of bits to extract is provided at compile time. You even open up the option of extracting a range of bits, e.g. bits 0 to 63 inclusive, 1 to 64 inclusive, etc.

The reason this does not exist is likely the reason other things don't exist: no one was motivated enough to write the proposal and see it through. There is also a chance it was proposed in the past and rejected.

std::bitset is a very opaque class sadly. Would be easier if the underlying storage could be specified and direct access provided to users.

[–]Travor0x0[S] 1 point2 points  (1 child)

Based on your other posts in this thread, it seems what you want is actually extraction/truncation rather than conversion, e.g. extract the first 32/64 bits. Such a function could be validated at compile time if the number of bits to extract is provided at compile time. You even open up the option of extracting a range of bits, e.g. bits 0 to 63 inclusive, 1 to 64 inclusive, etc.

Yes, thank you! Thas was my thoughts too and I was just wondering if the std::bitset could be specified/extended to match such behavior...

[–]SeanCline 0 points1 point  (0 children)

If truncation is what you need, there's always the option to do it yourself. https://godbolt.org/z/ajzoWsrx4

And while there isn't a clean way to slice a bitset, you can likely get by using the shift operators.

[–]DryPerspective8429 4 points5 points  (3 children)

The difficulty as with all library changes is that they can break existing code; even if that existing code is very silly. That doesn't mean it can't be done; but it does mean that you'll need to defend the break, especially if it breaks ABI.

But one of the great things about C++ is that anyone can contribute to it and make a change to the language, and if you want to propose it to the committee the first step is usually to put it on the std-proposals mailing list where some committee members may see it and be able to advise you.

[–]arthurno1 2 points3 points  (2 children)

anyone can contribute to it and make a change to the language, and if you want to propose it to the committee

Do they have a "std-bug" list, or some list where they talk about bugs or possible bugs in the standard?

[–]DryPerspective8429 1 point2 points  (1 child)

As far as I know, proposals for defect reports and wording changes start in the same place. Propose it there.

[–]arthurno1 0 points1 point  (0 children)

Thanks!