std::variant reflection. How can I tell which type of value std::variant is assigned? : <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>
