Skip to content

Instantly share code, notes, and snippets.

@Crspy
Last active November 18, 2020 14:32
Show Gist options
  • Select an option

  • Save Crspy/f9c1f9a03e84741f68f66874fc1d60fb to your computer and use it in GitHub Desktop.

Select an option

Save Crspy/f9c1f9a03e84741f68f66874fc1d60fb to your computer and use it in GitHub Desktop.
C++11 constexpr numbers (any base) to string (array of chars) conversion also supports prefixes
#include <cstdio>
#include <cstdint>
#include <type_traits>
namespace fast
{
namespace detail
{
constexpr auto numbers = "0123456789ABCDEF";
template <bool prefixed, uint8_t base, uint8_t... digits>
struct positive_to_chars
{
static const char value[];
};
template <bool prefixed, uint8_t base, uint8_t... digits>
const char positive_to_chars<prefixed, base, digits...>::value[] = {(numbers[digits])..., 0};
// zero case
template <bool prefixed, uint8_t base>
struct positive_to_chars<prefixed,base>
{
static const char value[];
};
template <bool prefixed, uint8_t base>
const char positive_to_chars<prefixed, base>::value[] = {'0', 0};
template <uint8_t... digits>
struct positive_to_chars<true, 2, digits...>
{
static const char value[];
};
template <uint8_t... digits>
const char positive_to_chars<true, 2, digits...>::value[] = {'0', 'b', (numbers[digits])..., 0};
template <uint8_t... digits>
struct positive_to_chars<true, 16, digits...>
{
static const char value[];
};
template <uint8_t... digits>
const char positive_to_chars<true, 16, digits...>::value[] = {'0', 'x', (numbers[digits])..., 0};
// negative numbers
template <uint8_t base, uint8_t... digits>
struct negative_to_chars
{
static const char value[];
};
template <uint8_t base, uint8_t... digits>
const char negative_to_chars<base, digits...>::value[] = {'-', (numbers[digits])..., 0};
template <uint8_t base, bool prefix, bool neg, uint8_t... digits>
struct to_chars : positive_to_chars<prefix, base, digits...>
{
};
template <uint8_t base, uint8_t... digits>
struct to_chars<base, true, false, digits...> : positive_to_chars<true, base, digits...>
{
};
template <uint8_t base, bool prefix, uint8_t... digits>
struct to_chars<base, prefix, true, digits...> : negative_to_chars<base, digits...>
{
};
template <uint8_t base, bool prefix, bool neg, uintmax_t rem, uint8_t... digits>
struct to_digits : to_digits<base, prefix, neg, rem / base, rem % base, digits...>
{
};
template <uint8_t base, bool prefix, bool neg, uint8_t... digits>
struct to_digits<base, prefix, neg, 0, digits...> : to_chars<base, prefix, neg, digits...>
{
};
template <typename T, T num>
constexpr uintmax_t cabs()
{
return (num < 0) ? -static_cast<uintmax_t>(num) : num;
}
template <typename T, T num>
constexpr typename std::make_unsigned<T>::type binary_cabs()
{
return static_cast<typename std::make_unsigned<T>::type>(num);
}
} // namespace detail
template <typename T, T num, uint8_t base = 10, bool prefix = false>
struct to_string
: detail::to_digits <
base,
prefix,
num<0 && base == 10,
base == 10 ? detail::cabs<T, num>() : detail::binary_cabs<T, num>()>
{
static_assert(
base == 2 ||
base == 4 ||
base == 8 ||
base == 10 ||
base == 16,
"base has to be one of the following {2,4,8,10,16}");
};
} // namespace fast
int main() {
using namespace fast; // couldn't find a good name for the namespace xD
// generates compiler warning or an error (depending on the compiler) that an overflow happened
constexpr auto str3 = to_string<signed char, -128, 10>::value;
printf("%s\n",str3);
constexpr auto str12 = to_string<signed char, 127, 2 , true>::value; // 0b1111111
printf("%s\n",str12);
constexpr auto str8 = to_string<int, -2147483648, 10>::value;
printf("%s\n",str8);
constexpr auto str9 = to_string<int, 2147483647, 10>::value;
printf("%s\n",str9);
constexpr auto str10 = to_string<int, -1, 16, true>::value; // 0xFFFFFFFF
printf("%s\n",str10);
constexpr auto str11 = to_string<char, -1, 16>::value; // FF
printf("%s\n",str11);
constexpr auto str4 = to_string<unsigned int, 4294967295, 10>::value;
printf("%s\n",str4);
// generates compiler warning or an error (depending on the compiler) that an overflow happened
// constexpr auto str6 = to_string<unsigned int, 4294967296, 10>::value;
// printf("%s\n",str6);
constexpr auto str7 = to_string<long long, 9223372036854775807, 10>::value;
printf("%s\n",str7);
constexpr auto str5 = to_string<int, 0, 10>::value;
printf("%s\n",str5);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment