Reputation: 73
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
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