title: How to specialise the return type of a function with an enum in C++?
body: <p>I'm using a variant to store a range of types for a syntax parser in C++. Each constituent of a syntax rule has a category (of type enum) and a value. The constituent stores a type of value according to the category. For the sake of example I've simplified the categories to 'String' => stores a string, and 'Number' => stores an int.</p>
  
  <p>I would like to get the value of the constituent with the correct type according to its category enum. How can I do this?</p>
  
  <p>I've written example code below, where I construct two constituents: strCon, storing a string, and intCon, storing an int, and attempt to get their values.</p>
  
  <p>I want to assign the string in strCon into strVal,
  and the int from intCon into intVal.</p>
  
  <pre class="lang-cpp prettyprint-override"><code>#include &lt;variant&gt;
  
  struct Constituent
  {
      enum class Category {String, Number};
      using Value = std::variant&lt;std::string, int&gt;;
  
      Category cat;
      Value val;
  
      // Using a struct ideally to allow partial specialisation of the template,
      // so I can pass the enum without the return type.
      template&lt;Category T&gt;
      struct OfCategory {};
  
      template&lt;Category T, typename U&gt;
      friend U const&amp; getValue(OfCategory&lt;T&gt;, Constituent const&amp;);
  }
  
  using Category = Constituent::Category;
  
  // Template to return the value as the correct type
  // for the constituent's category.
  template&lt;Category T, typename U&gt;
  U const&amp; getValue(OfCategory&lt;T&gt; type, Constituent const&amp; constituent)
  {
      // Uses the variant's get function.
      return std::get&lt;U&gt;(constituent.val);
  }
  
  // Specialisation to return string from Category::String.
  template&lt;&gt;
  string const&amp; getValue(OfCategory&lt;Category::String&gt; type,
      Constituent const&amp; constituent)
  {
      return getValue&lt;Category::String, string&gt;(constituent);
  }
  
  // Specialisation to return int from Category::Number.
  template&lt;&gt;
  int const&amp; getValue(OfCategory&lt;Category::Number&gt; type,
      Constituent const&amp; constituent)
  {
      return getValue&lt;Category::Number, int&gt;(constituent);
  }
  
  int main()
  {
      Constituent strCon = {Category::String, "This is a string!"};
      Constituent intCon = {Category::Number, 20};
  
      // In my current implementation, I want this to work with
      // the type wrapper as an overload for the function.
      string strVal = getValue(OfCategory&lt;Category::String&gt;{}, strCon);
      int intVal = getValue(OfCategory&lt;Category::Number&gt;{}, intCon);
  
      // But it would be better to directly use the template.
      strVal = getValue&lt;Category::String&gt;(strCon);
      intVal = getValue&lt;Category::Number&gt;(intCon);
  
      // The only way I can get it to work, is to explicitly provide
      // the return type, which defeats the point.
      strVal = getValue&lt;Category::String, string&gt;(
          OfCategory&lt;Category::String&gt;{}, strCon);
      intVal = getValue&lt;Category::Number, int&gt;(
          OfCategory&lt;Category::Number&gt;{}, intCon);
  
      // Ideally, I could use the cat parameter in Constituent to dynamically
      // infer the return type, but I don't believe something like this is
      // possible in C++.
  }
  </code></pre>