I was toying a lot with this, and so far I have an incomplete answer but some better c++ template wizards can help me. The current code should work for std containers. It still needs work to properly allow things i can get a range from, but this helps me move forward with the desired syntax.
//This structure will take a variant that can contains containers with the same
//value_type (ints, size_t, floats, whatever). It will create a "variant iterator"
//using the variadic template and the iterator_t helper.
template <typename... ContainerTypes>
struct IterableVariantWrapper {
//This is the part that i have to figure out yet. If the contained type
//is NOT a container, but i can obtain a range from it, i'd like to
//still allow it, but haven't found the way yet.
using VariantIter = std::variant<const_iterator_t<ContainerTypes>...>;
//Original variant we want to iterate over.
const std::variant<ContainerTypes...>& iterable;
//The iterator
struct iterator {
VariantIter iter;
bool operator!=(
const iterator& other) const
{
return iter != other.iter;
}
iterator operator++()
{
auto advanceIter = [](auto& v) -> void { ++v; };
std::visit(advanceIter, iter);
return *this;
}
auto operator*() const
{
auto returnElem = [](const auto& v) { return *v; };
return std::visit(returnElem, iter);
}
};
auto begin()
{
auto getBegin = [](const auto& v) -> VariantIter {
VariantIter iter = v.begin();
return iter;
};
return iterator { std::visit(getBegin, iterable) };
}
auto end()
{
auto getEnd = [](const auto& v) -> VariantIter { return v.end(); };
return iterator { std::visit(getEnd, iterable) };
}
};
//Calling this with a variant that contains a container where the contained
//type is the same will build the IterableVariantWrapper structure and provide
//a range-like object
template <typename... ContainerTypes>
auto getVariantRange(
const std::variant<ContainerTypes...>& variant)
{
return IterableVariantWrapper { variant };
}
I was thinking that maybe having a function/struct where i could ask the type of the view i can obtain from the iterated objects may be a way to go, but I couldn't get the syntax down. For example having a function for each type that is contained in the variant where the function returns either the same object if it is already a range, or a view derived from it, and then the variant iterator deduces the types from the return type of that function.
As i see, also I still need to figure put how to support actual ranges where the sentinel is a different type too, which i guess will be the next step after the previous paragraph.
A link to a working example using this: https://godbolt.org/z/qhrbP1se6
Any comment for further improvement is greatly appreciated.