What's the purpose of std::to_integer?

Viewed 7745

As far as I know, std::to_integer<T> is equivalent to T(value) where value is a variable having type std::byte.
I looked into some implementations from the major compilers and found that in this case equivalent means literally implemented as. In other terms, most of the times to_integer is actually implemented as:

return T(value);

And that's all.

What I don't understand is what's the purpose of such a function?
Ironically the cons are even more than the pros. I should include a whole header for such a function just to avoid a C-like cast that is most likely directly inlined anyway.

Is there any other reason for that or it's just really a nice looking alternative for a C-like cast and nothing more?

4 Answers

it's just really a nice looking alternative for a C-like cast and nothing more?

You say that as though it's some trivial detail.

Casts are dangerous. It's easy to cast something to the wrong type, and often compilers won't stop you from doing exactly that. Furthermore, because std::byte is not an integral type in C++, working with numerical byte values often requires a quantity of casting. Having a function that explicitly converts to integers makes for a safer user experience.

For example, float(some_byte) is perfectly legal, while to_integer<float>(some_byte) is explicitly forbidden. to_integer<T> requires that T is an integral type.

to_integer is a safer alternative.

I should include a whole header for such a function

If by "whole header", you mean the same header you got std::byte from and therefore is already by definition included...

std::to_integer<T>(some_byte) is equivalent to T(some_byte) if it actually compiles. T(some_byte) is equivalent to the unsafe C-style cast of (T)some_byte, which can do scary things. On the other hand, std::to_integer is appropriately constrained to only work when it is safe:

This overload only participates in overload resolution if std::is_integral_v<IntegerType> is true.

If the T was not actually an integer type, rather than potentially having undefined behavior, the code won't compile. If the some_byte was not actually a std::byte, rather than potentially having undefined behavior, the code won't compile.

Beyond the expression of intent and safety issues already mentioned, I get the idea from the committee discussion on the paper that it’s meant to be like std::to_string and might have more overloads in the future.

A C style cast is not equivalent to std::to_integer<T>. See the below example.

std::to_integer<T> only participates in overload resolution if std::is_integral_v<T> is true.

#include <cstddef>
#include <iostream>

template <typename T>
auto only_return_int_type_foo(std::byte& b)
{
    return std::to_integer<T>(b);
}

template <typename T>
auto only_return_int_type_bar(std::byte& b)
{
    return T(b);
}

int main()
{
    std::byte test{64};
    // compiles
    std::cout << only_return_int_type_foo<int>(test) << std::endl;

    // compiler error
    std::cout << only_return_int_type_foo<float>(test) << std::endl;

    // compiles
    std::cout << only_return_int_type_bar<int>(test) << std::endl;

    // compiles
    std::cout << only_return_int_type_bar<float>(test) << std::endl;
} 
Related