title: How do you implement compile-time string conversion functions?
body: <p>Proposal <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4121.pdf" rel="nofollow">n4121</a> looks like it's going to add a <code>std::string_literal</code> type. It contains code like:</p>
  
  <pre><code>template&lt;size_t n&gt; struct string_literal { char data [n]; }
  </code></pre>
  
  <p>and:</p>
  
  <pre><code>template &lt;size_t N&gt; 
  constexpr int stoi( const string_literal&lt;N&gt;&amp; str, 
                      size_t* idx = 0, int base = 10); 
  </code></pre>
  
  <p>And here's my Number class:</p>
  
  <pre><code>template &lt;typename T&gt;
  struct Number
  {
  private:
      T t;
  public:
      constexpr Number(const T&amp; t)
          : t(t)
      {
      }
  
      constexpr Number(const std::string&amp; s);
  
      constexpr operator T() const
      {
          return t;
      }
  };
  
  template &lt;&gt;
  constexpr Number&lt;int&gt;::Number(const std::string&amp; s)
      : t(std::stoi(s))
  {
  }
  </code></pre>
  
  <p>I've taken a look at <a href="https://stackoverflow.com/questions/25195176/how-do-i-convert-a-c-string-to-a-int-at-compile-time">How do I convert a C string to a int at compile time?</a> but it only works for C strings. and <code>c_str()</code> is non-constexpr. Also on top of that, this doesn't cover <code>stol</code>, <code>stoul</code>, <code>stoll</code>, <code>stof</code>, <code>stod</code>... and so on. Who knows if this proposal will make it into the standard. Also I don't want to wait 3 years for this library change to happen. How do I implement it in the moment, now?</p>
  
  <hr />
  
  <p>Here's my attempt so far:</p>
  
  <pre><code>namespace lib
  {
      constexpr bool is_digit(char c) {
          return c &lt;= '9' &amp;&amp; c &gt;= '0';
      }
  
      constexpr int stoi_impl(const char* str, int value = 0) {
          return *str ?
                  is_digit(*str) ?
                      stoi_impl(str + 1, (*str - '0') + value * 10)
                      : throw "compile-time-error: not a digit"
                  : value;
      }
  
      constexpr int stoi(const char* str) {
          return stoi_impl(str);
      }
  
      template&lt;size_t n&gt; struct string_literal { char data [n]; };
  
      template &lt; class charT, size_t N&gt; 
      constexpr string_literal&lt;N&gt; 
          make_string_literal( const charT(&amp;arr)[N])
          {
              string_literal&lt;N&gt; sl;
              for (std::size_t i = 0; i &lt; N; ++i)
                  sl.data[i] = arr[i];
              return sl;
          }
  }
  
  template &lt;typename T&gt;
  struct Number
  {
  private:
      T t;
  public:
      constexpr Number(const T&amp; t)
          : t(t)
      {
      }
  
      constexpr Number(const std::size_t N, const lib::string_literal&lt;N&gt;&amp; s);
  
      constexpr operator T() const
      {
          return t;
      }
  };
  
  template &lt;&gt;
  constexpr Number&lt;int&gt;::Number(const std::size_t N, const lib::string_literal&lt;N&gt;&amp; s)
      : t(lib::stoi(s.data))
  {
  }
  
  int main()
  {
      constexpr auto s = lib::make_string_literal("123456789");
      constexpr Number&lt;int&gt; n { sizeof(s.data), s };
  
      return 0;
  }
  
  main.cpp:44:69: error: non-type template argument is not a constant expression
      constexpr Number(const std::size_t N, const lib::string_literal&lt;N&gt;&amp; s);
                                                                      ^
  main.cpp:53:78: error: non-type template argument is not a constant expression
  constexpr Number&lt;int&gt;::Number(const std::size_t N, const lib::string_literal&lt;N&gt;&amp; s)
                                                                               ^
  main.cpp:29:38: error: cannot initialize an array element of type 'char' with an lvalue of type 'const char [10]'
              return string_literal&lt;N&gt;{arr};
                                       ^~~
  main.cpp:60:19: note: in instantiation of function template specialization 'lib::make_string_literal&lt;char, 10&gt;' requested here
      auto s = lib::make_string_literal("123456789");
  </code></pre>