C++ 现代迭代c++;带过滤器的收集

C++ 现代迭代c++;带过滤器的收集,c++,stl,iterator,C++,Stl,Iterator,假设我有这个班级设计 class A {}; class B : public A {}; class C : public A {}; 还有一个像这样的容器 std::list<A *> elements; std::列出元素; 现在我想要实现的是遍历容器中的所有B对象,或者在另一个时间遍历所有C对象 经典的方法是 for (auto it = elements.begin(); it != elements.end(); ++it) { B * b = dynamic_

假设我有这个班级设计

class A {};
class B : public A {};
class C : public A {};
还有一个像这样的容器

std::list<A *> elements;
std::列出元素;
现在我想要实现的是遍历容器中的所有B对象,或者在另一个时间遍历所有C对象

经典的方法是

for (auto it = elements.begin(); it != elements.end(); ++it) {
  B * b = dynamic_cast<B *>(*it);
  if (b) {
    // do stuff
  }
}
for(auto-it=elements.begin();it!=elements.end();++it){
B*B=动态_-cast(*it);
如果(b){
//做事
}
}
我想到的一个想法是创建一个迭代器类,该类派生自过滤的标准,但这很困难。 C++语言水平没有限制(C++ 5月20日也可以,但是看到C++ 11的回答会很棒)。
请用C++和STL(我知道Boost有一些前缀,但是构造)。

< P>我认为C++ 11的方式和它的接近,但我可能错了。C++17极大地扩展了,因此可以使用
std::for_each

为了演示这一点,让我们为这些类提供一些功能,并创建一个实例向量(或列表):

class A {
public:
    virtual std::string name() const = 0;
};
class B : public A {
public:
    virtual std::string name() const override {
        return "Class B";
    }
};
class C : public A {
public:
    virtual std::string name() const override {
        return "Class C";
    }
};

int main()
{
    std::vector<A*> vec { new B(), new B(), new C(), new C(), new B() };
}
不幸的是,任何算法都没有内置过滤器。但是,如果,您可以为每个_实现类似的

template<typename Iterator, typename Predicate, typename Operation> void 
for_each_if(Iterator begin, Iterator end, Predicate pred, Operation op) {
    std::for_each(begin, end, [&](const auto p) {
        if (pred(p))
            op(p);
    });
}
模板无效
for_每个_if(迭代器开始、迭代器结束、谓词pred、操作op){
标准::对于每个(开始、结束、[&](常数自动p){
if(pred(p))
op(p);
});
}
然后像这样使用它:

for_each_if(std::begin(vec), std::end(vec), 
    [](A* val) { return dynamic_cast<B*>(val) != nullptr; },
    [](const A* val) {
        std::cout << val->name() << std::endl;
    }
);
对于每个if(标准::开始(vec),标准::结束(vec),
[](A*val){return dynamic_cast(val)!=nullptr;},
[](常数A*val){

std::cout name()如果设计正确,则无需强制转换:

struct A { 
    virtual void doSomethingWithB() = 0;
    virtual ~A() = default;
};
struct B : A {
    void doSomethingWithB() override {
        // do somehting
    }
};
struct C : A {
    void doSomethingWithB() override {
       // do nothing !
    }
};
那么您的循环就是:

for (auto elem : elements) {
    elem->doSomethingWithB();
}

其中一个可能的解决方案是不使用动态类型转换。但是应该注意在派生类构造函数中声明正确的类型

如果列表中实际存储了类对象,我建议使用std::unique\u ptr

class Base
{
public:
  enum class Type
  {
    A,
    B,
    C
  };
  Base() = delete;
  virtual ~Base() = default;    
  Type type() const { return _type; }

protected:
  Base(Type type) : _type{type} {}  

private:
  Type _type;
};

class A : public Base
{
public:
  A() : Base{Base::Type::A} {}
};

class B : public Base
{
public:
  B() : Base{Base::Type::B} {}
};
class C : public Base
{
public:
  C() : Base{Base::Type::C} {}
};
            
    void function() 
    {
       std::list<std::unique_ptr<Base>> list;
       list.emplace_back(std::make_unique<A>());
       list.emplace_back(std::make_unique<B>());
       list.emplace_back(std::make_unique<C>());
                   
       // use non-const iterators if you intend to modify the object
       std::for_each(std::cbegin(list), std::cend(list),
                     [](const auto &item)
                     {
                       switch (item->type()) 
                       {
                         case Base::Type::B: 
                         {
                           assert(dynamic_cast<B*>(item.get()));
                           const auto &b = static_cast<B*>(item.get());
                           // do staff with b
                           break;
                         }
          
                         default:
                           return;
                         }                          
                   });
    }
类基
{
公众:
枚举类类型
{
A.
B
C
};
Base()=删除;
virtual~Base()=默认值;
Type Type()常量{return\u Type;}
受保护的:
基(类型):_类型{Type}{}
私人:
类型_类型;
};
A类:公共基地
{
公众:
A():Base{Base::Type::A}{}
};
B类:公共基地
{
公众:
B():Base{Base::Type::B}{}
};
丙级:公共基地
{
公众:
C():Base{Base::Type::C}{}
};
空函数()
{
std::列表;
list.emplace_back(std::make_unique());
list.emplace_back(std::make_unique());
list.emplace_back(std::make_unique());
//如果要修改对象,请使用非常量迭代器
std::for_each(std::cbegin(列表),std::cend(列表),
[](常量自动和项目)
{
开关(项目->类型())
{
案例库::类型::B:
{
断言(dynamic_cast(item.get());
const auto&b=静态_cast(item.get());
//和b一起工作吗
打破
}
违约:
返回;
}                          
});
}

可能的c++20实现使用范围

#include <iostream>
#include <list>
#include <ranges>

struct A {
  virtual ~A() = default;
};
struct B : public A {
  void foo() const { std::cout << "B\n"; }
};
struct C : public A {};

int main() {
  std::list<A *> demo{new A{}, new B{}, new C{}, new B{}};
  auto is_B = [](const A *p) { return dynamic_cast<const B *>(p) != nullptr; };
  auto get_B_const = [](const A *p) { return dynamic_cast<const B *>(p); };

  for (auto p_B :
       demo | std::views::filter(is_B) | std::views::transform(get_B_const)) {
    p_B->foo();
  }
  // demo destruction with delete not shown
}
#包括
#包括
#包括
结构A{
virtual~A()=默认值;
};
结构B:公共A{

void foo()const{std::cout我可以加2美分:通常这闻起来像是一个设计缺陷(当然也有例外),这个“异种容器”的问题,到目前为止还没有一个“好”的解决方案。我在荒野中看到的是,在所有元素的
std:vector va
之上,您可以只使用“B*”来维护另一个向量对象,
std::vector vb
,何时迭代go for
vb
何时删除go for
va

你能告诉我们你想在循环中做什么吗?因为在我的例子中,可能只声明一个接口就足够了。我的例子主要是枚举,但我想概括一下。我的具体情况如下:base为Property,派生为DisplayProperty、behaviorProperty、EventsProperty。所有这些都在属性集合中,但假设在一个窗口中,我只想显示应用的所有DisplayProperty。如果有某种视图仅在内容上列出该类型,那就太好了。保留不同的容器当然是可能的解决方案,到目前为止,c++20范围内的视图似乎是一个很好的方法,可以在关系数据库及其视图中找到一种模式。请注意,my是一个实用的示例,但它也可以应用于同质容器。例如,让我们对具有特定特征的每个元素创建一个相同类的容器和一个迭代器ry neat,我喜欢这段代码的简洁性和自动解释性。我正在尝试自己在范围上做文档记录,但我不明白迭代器(在您的示例中为p_B)是否可以用于来回移动,或者这种技术是否可以只枚举包含的每个元素。谢谢,查看您的解决方案让我找到了实现的可能方法“PyPube”老C++编译器()你是正确的,但是这个设计也有问题,那就是如果想添加一个新的D,那么我必须改变一个doSomethingWithD@FabioC实际的问题似乎是,您试图将不同的类压缩到一个基类中,而它们实际上没有任何共同点;)事实上正是如此。更准确地说,这是一个伪html解析器,我在列表中读取每个实体。有时是节点,有时是属性,有时是注释。我想按读取顺序保留每个元素的树,但有时我需要只迭代节点,有时只迭代元素,有时只迭代mes仅提供注释。可能是从某个元素我希望看到前面的注释
struct A { 
    virtual void doSomethingWithB() = 0;
    virtual ~A() = default;
};
struct B : A {
    void doSomethingWithB() override {
        // do somehting
    }
};
struct C : A {
    void doSomethingWithB() override {
       // do nothing !
    }
};
for (auto elem : elements) {
    elem->doSomethingWithB();
}
class Base
{
public:
  enum class Type
  {
    A,
    B,
    C
  };
  Base() = delete;
  virtual ~Base() = default;    
  Type type() const { return _type; }

protected:
  Base(Type type) : _type{type} {}  

private:
  Type _type;
};

class A : public Base
{
public:
  A() : Base{Base::Type::A} {}
};

class B : public Base
{
public:
  B() : Base{Base::Type::B} {}
};
class C : public Base
{
public:
  C() : Base{Base::Type::C} {}
};
            
    void function() 
    {
       std::list<std::unique_ptr<Base>> list;
       list.emplace_back(std::make_unique<A>());
       list.emplace_back(std::make_unique<B>());
       list.emplace_back(std::make_unique<C>());
                   
       // use non-const iterators if you intend to modify the object
       std::for_each(std::cbegin(list), std::cend(list),
                     [](const auto &item)
                     {
                       switch (item->type()) 
                       {
                         case Base::Type::B: 
                         {
                           assert(dynamic_cast<B*>(item.get()));
                           const auto &b = static_cast<B*>(item.get());
                           // do staff with b
                           break;
                         }
          
                         default:
                           return;
                         }                          
                   });
    }
#include <iostream>
#include <list>
#include <ranges>

struct A {
  virtual ~A() = default;
};
struct B : public A {
  void foo() const { std::cout << "B\n"; }
};
struct C : public A {};

int main() {
  std::list<A *> demo{new A{}, new B{}, new C{}, new B{}};
  auto is_B = [](const A *p) { return dynamic_cast<const B *>(p) != nullptr; };
  auto get_B_const = [](const A *p) { return dynamic_cast<const B *>(p); };

  for (auto p_B :
       demo | std::views::filter(is_B) | std::views::transform(get_B_const)) {
    p_B->foo();
  }
  // demo destruction with delete not shown
}
 auto get_B_const = [](const A *p) { 
    assert(dynamic_cast<const B *>(p));
    return static_cast<const B *>(p);
 };