Я думаю, что в 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() };
}
Теперь, используя for_each
, вы можете переписать свой l oop:
std::for_each(std::begin(vec), std::end(vec), [](const A* val) {
auto B* b = dynamic_cast<B*>(val);
if (b)
std::cout << b->name() << std::endl;
});
К сожалению, нет встроенного фильтра для любого из алгоритмы. Однако вы можете реализовать что-то вроде for_each_if
:
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_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;
}
);
Или для вашего конкретного случая c вы можете специализировать реализацию даже больше:
template<typename T, typename Iterator, typename Operation> void
dynamic_for_each(Iterator begin, Iterator end, Operation op) {
std::for_each(begin, end, [&](auto p) {
auto tp = dynamic_cast<T>(p);
if (tp)
op(tp);
});
}
и используйте его так:
dynamic_for_each<B*>(std::begin(vec), std::end(vec), [](const B* val) {
std::cout << val->name() << std::endl;
});
Все три реализации выводят один и тот же результат:
Class B
Class B
Class B