title: How to pass const char[] arrays as constexpr template parameters using C++ STL libraries?
body: <p>I have this working code for <strong><code>C++ 17</code></strong> standard:</p>
  
  <pre class="lang-cpp prettyprint-override"><code>template&lt; int PathIndex, int PathLength, const char (path)[PathLength] &gt;
  constexpr const int findlastslash()
  {
      if constexpr( PathIndex &lt; 1 || path[PathIndex] == '/' || path[PathIndex] == '\\' ) {
          return PathIndex;
      }
      else {
          return findlastslash&lt;PathIndex - 1, PathLength, path&gt;();
      }
  }
  
  template&lt; int PathLength, const char (path)[PathLength] &gt;
  constexpr const int startfindlastslash()
  {
      return findlastslash&lt; PathLength - 1, PathLength, path &gt;();
  }
  
  int main(int argc, char const *argv[]) {
      static constexpr const char path[7] = "c/test";
      static_assert( startfindlastslash&lt; 7, path &gt;() == 1, "Fail!" );
  }
  </code></pre>
  
  <p>I would like to stop writing/hard coding the <strong><code>constexpr</code></strong> array size <strong><code>7</code></strong>, i.e., make the template meta-programming deduce by itself the <strong><code>constexpr const char[]</code></strong> array size instead of having to write the size everywhere. For example, given something looking like the following:</p>
  
  <pre class="lang-cpp prettyprint-override"><code>template&lt; int PathIndex, int PathLength, const char (path)[PathLength] &gt;
  constexpr const int findlastslash()
  {
      if constexpr( PathIndex &lt; 1 || path[PathIndex] == '/' || path[PathIndex] == '\\' ) {
          return PathIndex;
      }
      else {
          return findlastslash&lt;PathIndex - 1, PathLength, path&gt;();
      }
  }
  
  template&lt; const char (path)[PathLength] &gt;
  constexpr const int startfindlastslash()
  {
      return findlastslash&lt; PathLength - 1, PathLength, path &gt;();
  }
  
  template&lt;int PathLength&gt;
  constexpr const char path[PathLength] = "c/test";
  
  int main(int argc, char const *argv[]) {
      static_assert( startfindlastslash&lt; path &gt;() == 1, "Fail!" );
  }
  </code></pre>
  
  <p>Of course, the code just above is utterly invalid. However, it is a good approximation of a easy way to describe things.</p>
  
  <p>How would you solve this problem? Would you replace <strong><code>constexpr const char path[7] = "c/test";</code></strong> by a <strong><code>std::array</code></strong> or <strong><code>std::string_view</code></strong>?</p>
  
  <p>I tried building this code using <strong><code>std::string_view</code></strong>:</p>
  
  <pre class="lang-cpp prettyprint-override"><code>#include &lt;string_view&gt;
  
  template&lt; int PathIndex, std::string_view path &gt;
  constexpr const int findlastslash()
  {
      if constexpr( PathIndex &lt; 1 || path[PathIndex] == '/' || path[PathIndex] == '\\' ) {
          return PathIndex;
      }
      else {
          return findlastslash&lt;PathIndex - 1, path&gt;();
      }
  }
  
  template&lt; std::string_view path &gt;
  constexpr const int startfindlastslash()
  {
      return findlastslash&lt; path.length() - 1, path &gt;();
  }
  
  int main(int argc, char const *argv[]) {
      static constexpr std::string_view path{"c/test"};
      static_assert( startfindlastslash&lt; path &gt;() == 1, "Fail!" );
  }
  </code></pre>
  
  <p>But it does not compile:</p>
  
  <ol>
  <li><p><strong><code>g++ -o main.exe --std=c++17 test_debugger.cpp</code></strong></p>
  
  <pre><code>test_debugger.cpp:3:43: error: ‘class std::basic_string_view&lt;char&gt;’ is not a valid type for a template non-type parameter
   template&lt; int PathIndex, std::string_view path &gt;
                                             ^~~~
  test_debugger.cpp:14:28: error: ‘class std::basic_string_view&lt;char&gt;’ is not a valid type for a template non-type parameter
   template&lt; std::string_view path &gt;
                              ^~~~
  test_debugger.cpp: In function ‘int main(int, const char**)’:
  test_debugger.cpp:22:47: error: no matching function for call to ‘startfindlastslash&lt;path&gt;()’
       static_assert( startfindlastslash&lt; path &gt;() == 1, "Fail!" );
                                                 ^
  test_debugger.cpp:15:21: note: candidate: template&lt;&lt;typeprefixerror&gt;path&gt; constexpr const int startfindlastslash()
   constexpr const int startfindlastslash()
                       ^~~~~~~~~~~~~~~~~~
  test_debugger.cpp:15:21: note:   template argument deduction/substitution failed:
  test_debugger.cpp:22:47: note: invalid template non-type parameter
       static_assert( startfindlastslash&lt; path &gt;() == 1, "Fail!" );
                                                 ^
  </code></pre></li>
  <li><p><strong><code>clang++ -Xclang -ast-print -fsyntax-only --std=c++17 test_debugger.cpp &gt; main.exe</code></strong></p>
  
  <pre><code>test_debugger.cpp:3:43: error: a non-type template parameter cannot have type 'std::string_view' (aka 'basic_string_view&lt;char&gt;')
  template&lt; int PathIndex, std::string_view path &gt;
                                            ^
  test_debugger.cpp:14:28: error: a non-type template parameter cannot have type 'std::string_view' (aka 'basic_string_view&lt;char&gt;')
  template&lt; std::string_view path &gt;
                             ^
  test_debugger.cpp:15:21: error: no return statement in constexpr function
  constexpr const int startfindlastslash()
                      ^
  test_debugger.cpp:22:20: error: no matching function for call to 'startfindlastslash'
      static_assert( startfindlastslash&lt; path &gt;() == 1, "Fail!" );
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~
  test_debugger.cpp:15:21: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'path'
  constexpr const int startfindlastslash()
                      ^
  4 errors generated.
  </code></pre></li>
  </ol>
  
  <p><strong>Note:</strong> I am not interested in finding the last slash on the string as the algorithm is doing. I just took this silly example as an excuse to learn better what can and cannot be done with constexpr template parameters.</p>
  
  <p>For reference, on <a href="https://www.reddit.com/r/cpp/comments/bhxx49/c20_string_literals_as_nontype_template/" rel="nofollow noreferrer">(C++20) String literals as non-type template parameters example?</a> I found this example code doing something cool with <strong><code>C++ 20</code></strong>: (<a href="https://godbolt.org/z/L0J2K2" rel="nofollow noreferrer">https://godbolt.org/z/L0J2K2</a>)</p>
  
  <pre class="lang-cpp prettyprint-override"><code>template&lt;unsigned N&gt;
  struct FixedString {
      char buf[N + 1]{};
      constexpr FixedString(char const* s) {
          for (unsigned i = 0; i != N; ++i) buf[i] = s[i];
      }
      constexpr operator char const*() const { return buf; }
  };
  template&lt;unsigned N&gt; FixedString(char const (&amp;)[N]) -&gt; FixedString&lt;N - 1&gt;;
  
  template&lt;FixedString T&gt;
  class Foo {
      static constexpr char const* Name = T;
  public:
      void hello() const;
  };
  
  int main() {
      Foo&lt;"Hello!"&gt; foo;
      foo.hello();
  }
  </code></pre>
  
  <p>Do I really need to define my own <strong><code>FixedString</code></strong> class? The <strong><code>C++ STL</code></strong> (Standard Template Library) does not have anything which can be used instead for this common/simple task?</p>
  
  <p>For reference, I found this nice related third part libraries:</p>
  
  <ol>
  <li><a href="https://github.com/irrequietus/typestring" rel="nofollow noreferrer">https://github.com/irrequietus/typestring</a> for <strong><code>C++11/14 strings for direct use in template parameter lists, template metaprogramming</code></strong>.</li>
  <li><a href="https://github.com/hanickadot/compile-time-regular-expressions" rel="nofollow noreferrer">https://github.com/hanickadot/compile-time-regular-expressions</a> <strong><code>A Compile time PCRE (almost) compatible regular expression matcher.</code></strong></li>
  </ol>