get currently held typeid of std::variant (like boost::variant type())
Asked Answered
H

2

8

I've migrated from boost::variant to std::variant, and hit a snag.

I was using a nice function in boost 'type()' that lets you get the currently held typeid. See https://www.boost.org/doc/libs/1_48_0/doc/html/boost/variant.html#id1752388-bb

How can this be achieved with std::variant?

I have an unordered map key'd on 'type_index', which holds some value 'std::function'. My variant, depending on the type, will determine what function I grab from the map to do some operation. (The code I have is far too large to post).

Any implementation ideas aside from writing a specific visitor for a particular std::variant? Maybe using the 'index()' function on the std::variant, to then index into the type list of the variant? Somewhat like this: How to get N-th type from a tuple?

Hasan answered 9/12, 2018 at 21:11 Comment(4)
There is no such method, use index or en.cppreference.com/w/cpp/utility/variant/get_if instead indeed.Midwest
I saw 'get-if' but it requires you to have knowledge of the variant types. I was hoping for a generic solution.Hasan
I'm not sure getting the type info was any more generic than get_if or index.Midwest
What's with the downvotes?Becky
E
14
template<class V>
std::type_info const& var_type(V const& v){
  return std::visit( [](auto&&x)->decltype(auto){ return typeid(x); }, v );
}

Alternatively

template<class...Ts>
std::type_info const& var_type(std::variant<Ts...> const& v, std::optional<std::size_t> idx={}){
  if (!idx) idx=v.index();
  if(*idx==std::variant_npos) return typeid(void);
  const std::array<std::type_info const*, sizeof...(Ts)> infos[]={ &typeid(Ts)... };
  return *(infos[*idx]);
}

Which lets you ask about other indexes that are not active.

Emission answered 9/12, 2018 at 23:5 Comment(3)
Nice, but what's with the std::optional? Lazy overloads?Veridical
@passer I thought "they can pass the index", then "but what if they don't want to". Hence what I wrote.Emission
Very nice, concise template solution!Hasan
B
4

The problem is that the currently-selected type is known only at runtime, whereas "obtaining" a type must be done at compile-time. This is exactly why we have visitors — to hide away the unavoidable chain of if statements behind the variant implementation.

Instead of re-inventing that implementation, it would be best to perform your map dispatching from inside such a visitor.

Failing that, you will have to write your own chain of if statements, producing code that's similar to the use of a visitor, but probably slower and less maintainable!

It is true that you can't implement such a thing by reading index() then asking the variant to give you equivalent typeid, as you could with the Boost implementation. But I'm pretty sure that's deliberate, because (as I've suggested above) any code making use of that would be ill-advised. Of course, if you really wanted to, you could write a visitor to produce such a typeid! But then you still have to write conditional logic to deal with that value, when you could have just put the logic into the visitor in the first place.

Becky answered 9/12, 2018 at 21:33 Comment(1)
I agree with what you wrote, but I selected the other answer as 'correct' since it has a code example for others to utilize with 'std::visit' that is generic (I gave an upvote for your answer)Hasan

© 2022 - 2024 — McMap. All rights reserved.