具有包含变体的向量的Remove_if

时间:2019-01-31 21:12:17

标签: c++ c++17 variant

我有两个不同的对象:

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::vector一起存储在std::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的谓词中刊登广告,还是可以吗?

2 个答案:

答案 0 :(得分:10)

是的,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将同时使用operator()TypeA实例化其模板TypeB

答案 1 :(得分:3)

如果要访问不同类型的“相同”数据成员,则这些类型需要是定义此数据成员的通用多态基类的子类。

但是,在您的情况下,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());