YesButWhy
YesButWhy

Reputation: 73

Return underlying value of boost::variant with boost::apply_visitor

Is it possible to code the write the boost:static_visitor so that it could return the underlying value of a boost::variant in a type-safe way? My current efforts to do that look as follows.

using EventData = boost::variant<boost::blank, int, std::string, boost::system::error_code>;

struct EventDataVisitor : public boost::static_visitor<> 
{
  int operator()(int number) const { return number; }
  SstErrors operator()(SstErrors err) const { return err; }
  boost::blank operator()(boost::blank) const { return boost::blank{}; }
  decltype(auto) operator()(const boost::system::error_code& ec) const { return ec; }
};

Next, I want to use the EventData variant as follows:

EventData data {"Hello world!"};
// ... Some code here ...

// Retrieve data of specific type later. 
// Should safely return the underlying value of a type it was initialized with.
std::string& eventDataString = boost::apply_visitor(EventDataVisitor{}, data)

If this is not possible, what is another safe way to retrieve the current value of the EventData? (With or better without enabling RTTI).

Upvotes: 1

Views: 255

Answers (1)

sehe
sehe

Reputation: 394054

You can't. If that were possible you wouldn't need variant.

Another way of putting it: you can but it requires you to return (another) variant, e.g.:

struct EventDataVisitor : public boost::static_visitor<boost::variant<boost::blank, int, SstErrors, boost::system::error_code> >
{
  int operator()(int number) const { return number; }
  SstErrors operator()(SstErrors err) const { return err; }
  boost::blank operator()(boost::blank) const { return boost::blank{}; }
  decltype(auto) operator()(const boost::system::error_code& ec) const { return ec; }
};

The usual approach is to pass a callback that is invoked with the active element type. This is exactly what the visitor interface is, but sometimes it might make sense to have a more specific interface.

If this is not possible, what is another safe way to retrieve the current value of the EventData? (With or better without enabling RTTI).

 EventData data {"Hello world!"};
 std::string& eventDataString = boost::get<std::string>(data);

That's safe. If there's more between the assignment and use, you might use the pointer versions of get<>:

 if (auto* p = boost::get<std::string>(&data)) {
      // contains a valid std::string
      std::string& eventDataString = *p;
 }

Upvotes: 1

Related Questions