title: returning string_view from function
body: <p>I am writing a lot of parser code where string_view excels, and have gotten fond of the type. I recently read ArthurO'Dwyer's article <a href="https://quuxplusone.github.io/blog/2018/03/27/string-view-is-a-borrow-type/" rel="nofollow noreferrer">std::string_view is a borrow type</a>, where he concludes that string_view (and other 'borrow types') are fine to use as long as they &quot;... appear only as function parameters and for-loop control variables.&quot; (with a couple of exceptions).</p>
  <p>However, I have lately started to use string_view as return value for functions that convert enum to string (which I use a lot), like this <a href="https://godbolt.org/z/TTWYd9x75" rel="nofollow noreferrer">Compiler Explorer</a>:</p>
  <pre><code>#include &lt;iostream&gt;
  #include &lt;string&gt;
  #include &lt;array&gt;
  #include &lt;algorithm&gt;
  
  enum class Color
  {
      red, green, blue, yellow,
      last // Must be kept last
  };
  constexpr std::string_view toString(Color color); 
  
  // The rest would normally be in a .cpp file
  
  using cts = std::pair&lt;Color, std::string_view&gt;;
  constexpr std::array colorNames = {cts{Color::red, &quot;red color&quot;},
                              cts{Color::green, &quot;green color&quot;},
                              cts{Color::blue, &quot;blue color&quot;},
                              cts{Color::yellow, &quot;yellow color&quot;}};
  
  static_assert(colorNames.size() == static_cast&lt;size_t&gt;(Color::last));
  
  constexpr std::string_view toString(Color color)
  {
      // Normally calling a library function (which also checks for no match), instead of this:
      return std::ranges::find(colorNames, color, &amp;cts::first)-&gt;second;
  }
  
  int main()
  {
      auto s1 = toString(Color::green);
      auto s2 = toString(Color::blue);
  
      std::cout &lt;&lt; s1 &lt;&lt; ' ' &lt;&lt; s2 &lt;&lt; std::endl;
  }
  </code></pre>
  <p>The reasons I have for doing it this way are:</p>
  <ol>
  <li>By having it stored in an array as string_view, I can make the entire table constexpr.</li>
  <li>By returning the string_view directly, there is no need of converting the string representation, so the entire function can be constexpr, or at least avoid creating unnecessary strings even when called with a non-constexpr parameter.</li>
  <li>A side effect of having the table constexpr is that I can use static_assert to check that all elements of the enum are in the table, which is really great for catching additions to the enum. I really don't like having to put the 'last' enum value in there, but I don't see a better solution.</li>
  </ol>
  <p><em><strong>So my question is really</strong></em>, is returning the string_view this way unsafe (or UB) in any way, or can I keep on doing this with good conscience?</p>
  <p>Alternatively, is there a better (faster/safer) way of solving this general problem of enum-to-string?</p>
  <p><em><strong>Addition</strong></em>: After reading G. Sliepen's very good answer, I'd like to add upon my comment to his answer: I often have the opposite function as well, e.g.:</p>
  <pre><code>constexpr Color fromString(string_view str)
  {
    // No-match handling omitted
    return std::ranges::find(colorNames, color, &amp;cts::second)-&gt;first;
  }
  </code></pre>
  <p>In those situations I really do need the translation as a separate table so that it can be used by both functions. But in many other cases, the function containing a switch statement is the simplest and best.</p>