2

I came across this post: Convert a number to a string literal with constexpr

And the answer is quite interesting:

namespace detail
{
    template<unsigned... digits>
    struct to_chars { static const char value[]; };

    template<unsigned... digits>
    const 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> {};

My questions are:

  1. "struct explode : explode" declares explode inherits from explode; how about "struct explode<0, digits...> : to_chars"?

  2. What's the function for the '0' as the first template parameter?

Thanks!

Community
  • 1
  • 1
Hei
  • 1,844
  • 3
  • 21
  • 35

1 Answers1

6

This is a recursive formula with a partial specialization that serves as a termination condition.

explode<1234>

inherits from:

explode<123, 4>          // 1234 / 10 = 123, 1234 % 10 = 4

inherits from:

explode<12, 3, 4>        // 123 / 10 = 12, 123 % 10 = 3

inherits from:

explode<1, 2, 3, 4>      // 12 / 10 = 1, 12 % 10 = 2

inherits from:

explode<0, 1, 2, 3, 4>   // 1 / 10 = 0, 1 % 10 = 1

At this point, the left-most value (referred to as rem in the primary template) is 0, so it matches the partial specialization:

template <unsigned... digits>
struct explode<0, digits...> : to_chars<digits...> {};

(indicating that the whole number was turned into separate digits) which eventually inherits from:

to_chars<1, 2, 3, 4>

Finally, to_chars expands the parameter pack into a char array, also turning the digits into characters, so that 1 becomes '1', 2 becomes '2', and so on:

const char to_chars<1, 2, 3, 4>::value[] = { '1', '2', '3', '4', 0 };

Here, 0 is the null terminating character, so that value can be treated as if it were a string.

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
  • Very interesting that it "keeps" inheriting from explode through variadiac template expansion and then inherits from a different struct at the end (base case). Thanks! – Hei Apr 26 '17 at 09:23