title: std::variant reflection. How can I tell which type of value std::variant is assigned?
body: <p>I have a class called <code>foo_t</code> that has a member called <code>bar</code> which could be any one of the types <code>std::string</code>, <code>int</code>, <code>std::vector&lt;double&gt;</code>, etc. I would like to be able to ask <code>foo_t</code> which type <code>bar</code> has been assigned to. I decided to use <code>std::variant</code>.</p>
  
  <p>I've written a solution, but I'm not sure if this is a good use of std::variant. I'm not sure if it matters, but I expect the list of types to possibly grow much bigger in the future. I made an enum class to store which type std::variant is assigned to. My first implementation also available on <a href="https://wandbox.org/permlink/pLshfzdpmv177KQf" rel="noreferrer">wandbox</a>:</p>
  
  <pre><code>#include &lt;iostream&gt;
  #include &lt;variant&gt;
  #include &lt;vector&gt;
  #include &lt;string&gt;
  
  enum foo_kind_t {
    double_list,
    name_tag,
    number,
    unknown
  };
  
  template &lt;typename val_t&gt;
  struct get_foo_kind_t {
    constexpr static foo_kind_t value = unknown;
  };
  
  template &lt;&gt;
  struct get_foo_kind_t&lt;int&gt; {
    constexpr static foo_kind_t value = number;
  };
  
  template &lt;&gt;
  struct get_foo_kind_t&lt;std::string&gt; {
    constexpr static foo_kind_t value = name_tag;
  };
  
  template &lt;&gt;
  struct get_foo_kind_t&lt;std::vector&lt;double&gt;&gt; {
    constexpr static foo_kind_t value = double_list;
  };
  
  class foo_t {
  
  public:
  
    foo_t(): kind(unknown) {}
  
    template &lt;typename val_t&gt;
    void assign_bar(const val_t &amp;val) {
      static_assert(get_foo_kind_t&lt;val_t&gt;::value != unknown, "unsupported assignment");
      kind = get_foo_kind_t&lt;val_t&gt;::value;
      bar = val;
    }
  
    foo_kind_t get_kind() {
      return kind;
    }
  
    template &lt;typename val_t&gt;
    val_t get_bar() {
      if (get_foo_kind_t&lt;val_t&gt;::value != kind) {
        throw std::runtime_error("wrong kind");
      }
      return std::get&lt;val_t&gt;(bar);
    }
  
  private:
  
    foo_kind_t kind;
  
    std::variant&lt;
      int,
      std::string,
      std::vector&lt;double&gt;
    &gt; bar;
  
  };
  
  template &lt;typename val_t&gt;
  void print_foo(foo_t &amp;foo) {
      std::cout &lt;&lt; "kind: " &lt;&lt; foo.get_kind() &lt;&lt; std::endl;
      std::cout &lt;&lt; "value: " &lt;&lt; foo.get_bar&lt;val_t&gt;() &lt;&lt; std::endl &lt;&lt; std::endl;
  }
  
  int main(int, char*[]) {
  
      // double_list
      foo_t b;
      std::vector&lt;double&gt; b_val({ 1.0, 1.1, 1.2 });
      b.assign_bar(b_val);
      std::cout &lt;&lt; "kind: " &lt;&lt; b.get_kind() &lt;&lt; std::endl;
      std::cout &lt;&lt; "value: vector size: " &lt;&lt; b.get_bar&lt;std::vector&lt;double&gt;&gt;().size() &lt;&lt; std::endl &lt;&lt; std::endl;
  
      // name_tag
      foo_t d;
      std::string d_val("name");
      d.assign_bar(d_val);
      print_foo&lt;std::string&gt;(d);
  
      // number
      foo_t c;
      int c_val = 99;
      c.assign_bar(c_val);
      print_foo&lt;int&gt;(c);
  
      // unknown
      foo_t a;
      std::cout &lt;&lt; a.get_kind() &lt;&lt; std::endl;
  
      return 0;
  }
  </code></pre>
  
  <p>Is this a good way to do it? Is there a way having better performance? Is there a way that requires less code to be written? Is there a way that doesn't require C++17?</p>