使用包含变量的向量进行remove_if操作

5

我有两个不同的对象:

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::variantstd::vector中。

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

现在我想要删除所有成员no = 0的元素。
如果没有只包含TypeA的向量的std::variant,我会这样做:
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的谓词中,或者可以吗?

2个回答

11

是的,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,它是通用的很重要,因为visit将实例化其模板operator()TypeATypeB


3
如果您想访问不同类型的“相同”数据成员,则这些类型需要是定义此数据成员的公共多态基类的子类。
然而,在您的情况下,其中TypeA和TypeB没有关联,您将必须对各自的数据成员进行类型安全访问。@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());

这只会带来麻烦。当你向变量添加第三种类型时会发生什么?你记得需要更新它吗?如果你要查找的类型不便宜复制呢?或者根本无法复制?或者没有默认构造函数呢? - Barry

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接