I have some variant using V = std::variant<A, B, C>
and a function with the prototype V parse(const json&)
. The function should try to parse all the types (e.g. A
, B
, then C
) till the first success (and it should do it implicitly, for there will be many types in time).
How to implement something of this kind?
We may use std::variant_size
somehow.
Here is something close to what I need.
My solution is to list parsers of all the types explicitly.
V parse(const json& i_j)
{
using Parser = std::function<MaybeV(const json&)>;
static const auto ps = std::vector<Parser>{
[](const auto& j)->MaybeV{return j.get<std::optional<A>>;},
[](const auto& j)->MaybeV{return j.get<std::optional<B>>;},
[](const auto& j)->MaybeV{return j.get<std::optional<C>>;}
};
for (const auto& p : ps)
if (auto opt_result = p(i_j))
return std::move(*opt_result);
throw ParseError("Can't parse");
}
Yet it may definitely be simplified, for the lambdas different only in type and what I actually need is to iterate over the types of std::variant
.
std::visit
should work. If the variant isn't initialized you shouldn't be parsing it. If you just mean no value that's a special case (seestd::variant::valueless_by_exception
) – Elevensesget<std::optional<T>>
for variousT
types onj
which isi_j
, the inputjson
object. Shouldn't that already be initialized? What we're returning is just the result of the first successful parser invocation (*
just dereferences thestd::optional
) – Elevensesstd::visit
then a generic visitor could be used and just return the A, B, C instance directly (or throw on none, etc.). That would avoid specifying any of the types anywhere – Elevenses.get<optional<T>>
, but not be handed back directly in visitation. That is, you could have a typeA
constructible from anint
, but if you visit the json and get anint
, you'd still have to go throughA
,B
, andC
checking whether you can construct them from thatint
. If you don't mean to visit the json object, then I'm not sure what you're suggesting to visit. – Novikoff