I'm looking for a way to convert a number to a string literal at compile time. It should look something like this:
template <unsigned num>
struct num_to_string {
constexpr static char value[] = /* ... magic goes here ... */;
};
So that num_to_string<5>::value
is equal to "5"
or {'5', '\0'}
.
This can be useful for generating a string at compile time from a number that is the result of some other constexpr number calculations.
Also note that I'm only interested in unsigned
numbers since that should be easier to deal with. Bonus points for the signed version :)
EDIT: Note that this is similar to C++ convert integer to string at compile time, but not the same. Here I explicitly want something that uses constexpr and not macros to aid in generic programming.
Variadic templates to the rescue. :)
namespace detail
{
template<unsigned... digits>
struct to_chars { static const char value[]; };
template<unsigned... digits>
constexpr char to_chars<digits...>::value[] = {('0' + digits)..., 0};
template<unsigned rem, unsigned... digits>
struct explode : explode<rem / 10, rem % 10, digits...> {};
template<unsigned... digits>
struct explode<0, digits...> : to_chars<digits...> {};
}
template<unsigned num>
struct num_to_string : detail::explode<num> {};
As always, here's a live example on Coliru showing usage and the (relevant) generated assembly.
It's straightforward to adapt this approach to support negative numbers as well. Here's a more generic form that requires the user to input the integer's type:
namespace detail
{
template<uint8_t... digits> struct positive_to_chars { static const char value[]; };
template<uint8_t... digits> constexpr char positive_to_chars<digits...>::value[] = {('0' + digits)..., 0};
template<uint8_t... digits> struct negative_to_chars { static const char value[]; };
template<uint8_t... digits> constexpr char negative_to_chars<digits...>::value[] = {'-', ('0' + digits)..., 0};
template<bool neg, uint8_t... digits>
struct to_chars : positive_to_chars<digits...> {};
template<uint8_t... digits>
struct to_chars<true, digits...> : negative_to_chars<digits...> {};
template<bool neg, uintmax_t rem, uint8_t... digits>
struct explode : explode<neg, rem / 10, rem % 10, digits...> {};
template<bool neg, uint8_t... digits>
struct explode<neg, 0, digits...> : to_chars<neg, digits...> {};
template<typename T>
constexpr uintmax_t cabs(T num) { return (num < 0) ? -num : num; }
}
template<typename Integer, Integer num>
struct string_from : detail::explode<(num < 0), detail::cabs(num)> {};
Its usage is like:
string_from<signed, -1>::value
as demonstrated in the live example on Coliru.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With