Reputation: 2210
I have this code:
std::vector<boost::variant<int,float,std::string>> data;
template<typename T> T Get(size_t i)
{
if (i < data.size())
return boost::get<T>(data[i]);
return T();
}
how can I check if get<T>
failed so I can return T()
(without exceptions as it's very costly for performance)?
Upvotes: 1
Views: 88
Reputation: 393613
In general you can't.
If you know the type indices, you can - perhaps - do something brittle with variant::which
.
The sure-fire way would be to write a visitor yourself though. Here's a proof of concept:
namespace detail {
template <typename T>
struct get_with_default_visitor : boost::static_visitor<T> {
T default_;
get_with_default_visitor(T dv) : default_(dv) {}
T const& operator()(T const& v) const { return v; }
template <typename Other> T operator()(Other const&) const {
return default_;
}
};
}
template<typename T, typename Container> T Get(Container const& data, size_t i, T defaultvalue = T())
{
if (i < data.size())
return boost::apply_visitor(detail::get_with_default_visitor<T>(defaultvalue), data[i]);
else
return defaultvalue;
}
See it Live On Coliru with
int main() {
std::vector<boost::variant<int, float, std::string> > data {
42, 3.14f, std::string("hello world") };
for (int i = 0; i < 5; ++i) std::cout << Get<int>(data, i, -99) << "\t";
std::cout << "\n";
for (int i = 0; i < 5; ++i) std::cout << Get<float>(data, i, -9999e99) << "\t";
std::cout << "\n";
for (int i = 0; i < 5; ++i) std::cout << "'" << Get<std::string>(data, i, "#error#") << "'\t";
std::cout << "\n";
}
Printing
42 -99 -99 -99 -99
-inf 3.14 -inf -inf -inf
'#error#' '#error#' 'hello world' '#error#' '#error#'
Upvotes: 1