Search code examples
c++c++17variant

Remove_if with vector containing variants


I have two different objects:

struct TypeA {
    std::size_t no;
    std::string data;
    std::string data2;
};

struct TypeB {
    std::size_t no;
    std::string data;
    std::string data2;
    std::string data3;
};

They are stored in a std::vector with std::variant

std::vector<std::variant< TypeA, TypeB>> ab;

Now i want to remove all elements were the member no = 0.

Without the std::variant with the vector containing only TypeA I would do it like this:

ab.erase(std::remove_if(ab.begin(), ab.end(),
    [](const TypeA& a) { return a.no == 0; }), ab.end());

But how to incorporate the std::variant ? I tried to come up with something with std::visit but i cannot ad it in the predicate of std::remove_if or can I?


Solution

  • Yes, std::visit can help. The functor passed to visit just needs to be able to accept each type of the variant, and the easiest way to do that is with a generic lambda:

    ab.erase(
        std::remove_if(
            ab.begin(),
            ab.end(),
            [](const auto &v) {
                return std::visit(
                    [](const auto &obj) { return obj.no == 0; },
                    v);
        }),
        ab.end());
    

    Here the type of v for the outer lambda is always used as const std::variant<TypeA, TypeB>&, and auto is just more convenient than typing out std::variant<TypeA, TypeB>. But for the inner lambda, it's important that the lambda is generic, because visit will instantiate its template operator() with both TypeA and TypeB.