Remove_if 向量包含变体

Remove_if with vector containing variants

我有两个不同的对象:

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;
};

它们存储在 std::vectorstd::variant

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

现在我想删除成员 no = 0 的所有元素。

如果没有 std::variant 且矢量只包含 TypeA 我会这样做:

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

但是如何合并 std::variant 呢?我试图用 std::visit 想出一些东西,但我不能在 std::remove_if 的谓词中添加它,或者我可以吗?

是的,std::visit 可以提供帮助。传递给 visit 的仿函数只需要能够接受 variant 的每种类型,最简单的方法是使用通用 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());

这里外层 lambda 的 v 类型总是使用 const std::variant<TypeA, TypeB>&,而 auto 只是比键入 std::variant<TypeA, TypeB> 更方便。但对于内部 lambda,重要的是 lambda 是通用的,因为 visit 将使用 TypeATypeB.

实例化其模板 operator()

如果要访问不同类型的 "same" 数据成员,则这些类型需要是定义此数据成员的公共多态基 class 的子class。

但是,在您的情况下,TypeATypeB 不相关,您必须对相应的数据成员进行类型安全访问。 @aschepler 提供的解决方案使用 std::visit 仿函数以通用方式显示了这一点;以下解决方案没有 std::visit (因此不是那么优雅,但仍然有效):

ab.erase(std::remove_if(ab.begin(), ab.end(),
    [](const std::variant< TypeA, TypeB>& v) { 
      int no;
      if (v.index()==0) {
         no = std::get<0>(v).no;
      } else {
         no = std::get<1>(v).no;
      }
      return no==0;
    }), ab.end());